CE Source C++.cpp 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Edit{
  5. /******************************************************************************/
  6. #define WRITE_SEPARATORS 0
  7. /******************************************************************************
  8. void write(CodeLine &cline, C VecI2 &start, C VecI2 &end);
  9. void write(CodeLine &cline, Int start, Int end);
  10. void Source::write(CodeLine &cline, C VecI2 &start, C VecI2 &end)
  11. {
  12. for(Int y=start.y; y<=end.y; y++)if(InRange(y, lines))
  13. {
  14. Line &l=lines[y]; cline.includeLine(y);
  15. Int start_x=((y==start.y) ? start.x : 0),
  16. end_x=((y== end.y) ? end.x : l.length()-1);
  17. for(Int x=start_x; x<=end_x; x++)if(l.Type(x)!=TOKEN_COMMENT)cline.cols.New().set(l[x], x, y, -1, l.Type(x));
  18. }
  19. }
  20. void Source::write(CodeLine &cline, Int start, Int end)
  21. {
  22. MAX(start, 0);
  23. MIN(end , tokens.elms()-1);
  24. if(InRange(start, tokens)
  25. && InRange(end , tokens))
  26. {
  27. for(Int i=start; start<=end; i++)
  28. {
  29. Token &token=*tokens [i];
  30. CChar8 *dot = adjustDot(i);
  31. if(dot || i==end)
  32. {
  33. Int to=(dot ? i-1 : i);
  34. VecI2 s, e; srcTokenRange(start, to, s, e); write(cline, s, e);
  35. if(dot)cline.append(dot, TOKEN_OPERATOR, i);
  36. start=i+1;
  37. }
  38. }
  39. }
  40. }
  41. /******************************************************************************/
  42. void Source::srcTokenRange(Int t_start, Int t_end, VecI2 &start, VecI2 &end)
  43. {
  44. Token //*p=(InRange(t_start-1, tokens) ? tokens[t_start-1] : null),
  45. &s=*tokens[t_start],
  46. &e=*tokens[t_end ],
  47. *n=(InRange(t_end+1, tokens) ? tokens[t_end+1] : null);
  48. if(s.macro_col>=0)start.set(s.macro_col, s.macro_line->line);
  49. else start.set(s.col , s.lineIndex() );
  50. if(n)end.set(n->col-1 , n->lineIndex()); // process from s to n-1
  51. else end.set(e.line->length()-1, e. lineIndex()); // process from s to end of line
  52. for(; lineValid(end); dec(end))
  53. {
  54. TOKEN_TYPE t=lines[end.y].Type(end.x);
  55. if(t!=TOKEN_NONE && t!=TOKEN_COMMENT)break; // don't include spaces or comments after the token
  56. }
  57. }
  58. Bool Source::destTokenRange(Memc<CodeLine> &clines, Int t_start, Int t_end, VecI2 &start, VecI2 &end)
  59. {
  60. if(InRange(t_start, tokens)
  61. && InRange(t_end , tokens))
  62. {
  63. // find by token indexes
  64. if(FindLineCol(clines, t_start, tokens[t_start]->lineIndex(), true , start))
  65. if(FindLineCol(clines, t_end , tokens[t_end ]->lineIndex(), false, end ))
  66. return true;
  67. // find by source text positions
  68. srcTokenRange(t_start, t_end, start, end); // convert tokens to positions (this already handles macro issues)
  69. if(FindLineCol(clines, start, start))
  70. if(FindLineCol(clines, end , end ))
  71. return true;
  72. }
  73. return false;
  74. }
  75. Str Source::getText(Int start, Int end)
  76. {
  77. Str out;
  78. MAX(start, 0);
  79. MIN(end , tokens.elms()-1);
  80. if(InRange(start, tokens)
  81. && InRange(end , tokens))
  82. {
  83. VecI2 s, e; srcTokenRange(start, end, s, e);
  84. write(out, s, e);
  85. }
  86. return out;
  87. }
  88. void Source::writeAll(Str &out, C VecI2 &start, C VecI2 &end)
  89. {
  90. Int start_y=Max(0, start.y), end_y=Min(end.y, lines.elms()-1);
  91. for(Int y=start_y; y<=end_y; y++)
  92. {
  93. if(y!=start_y)out+='\n';
  94. C Line &line=lines[y];
  95. for(Int max_x=((y==end .y) ? Min(end .x, line.length()) : line.length()),
  96. x=((y==start.y) ? Max(start.x, 0) : 0 ); x<max_x; x++)out+=line[x];
  97. }
  98. }
  99. void Source::write(Str &out, C VecI2 &start, C VecI2 &end)
  100. {
  101. for(Int y=start.y; y<=end.y; y++)if(InRange(y, lines))
  102. {
  103. C Line &l=lines[y];
  104. Int start_x=((y==start.y) ? start.x : 0),
  105. end_x=((y== end.y) ? end.x : l.length()-1);
  106. for(Int x=start_x; x<=end_x; x++)if(l.Type(x)!=TOKEN_COMMENT)
  107. {
  108. Char c=l[x];
  109. if(!(c==' ' && (out.last()==' ' || !out.is())))out+=c;
  110. }
  111. }
  112. if(out.last()==' ')out.removeLast();
  113. }
  114. // this method appends text starting from line_i inclusive
  115. void Source::write(Memc<CodeLine> &clines, C VecI2 &start, C VecI2 &end, VecI2 *clines_start, Int *line_i) // 'clines_start' position in 'clines' where first text was written
  116. {
  117. if(clines_start)*clines_start=-1; // set invalid at start in case no text is written
  118. Int li=(line_i ? *line_i : clines.elms());
  119. Bool wrote=false;
  120. for(Int y=start.y; y<=end.y; y++)if(InRange(y, lines))
  121. {
  122. C Line &l=lines[y];
  123. if(wrote)clines.NewAt(++li);else // if we're writing secondary line, then create new line
  124. {
  125. wrote=true;
  126. if(!InRange(li, clines))
  127. {
  128. clines.NewAt(li);
  129. Clamp(li, 0, clines.elms()-1);
  130. }
  131. }
  132. CodeLine &cl=clines[li].includeLine(y);
  133. Int start_x=((y==start.y) ? start.x : 0),
  134. end_x=((y== end.y) ? end.x : l.length()-1);
  135. if(y==start.y)
  136. {
  137. if(!cl.cols.elms())FREP(start_x)if(l[i]==' ')cl.append(' ', TOKEN_NONE);else break;
  138. if(clines_start)clines_start->set(cl.cols.elms(), li);
  139. }
  140. for(Int x=start_x; x<=end_x; x++)cl.cols.New().set(l[x], x, y, -1, l.Type(x));
  141. }
  142. if(line_i)*line_i=li;
  143. }
  144. void Source::write(Memc<CodeLine> &clines, Int start, Int end, VecI2 *clines_start, Int *line_i)
  145. {
  146. MAX(start, 0);
  147. MIN(end , tokens.elms()-1);
  148. if(InRange(start, tokens)
  149. && InRange(end , tokens))
  150. {
  151. VecI2 s, e; srcTokenRange(start, end, s, e);
  152. write(clines, s, e, clines_start, line_i);
  153. }else
  154. {
  155. if(clines_start)*clines_start=-1;
  156. }
  157. }
  158. void Source::writeTokens(CodeLine &cline, Int start, Int end, Bool gcc)
  159. {
  160. MAX(start, 0);
  161. MIN(end , tokens.elms()-1);
  162. if(InRange(start, tokens)
  163. && InRange(end , tokens))
  164. {
  165. Str temp;
  166. TOKEN_TYPE last_type=TOKEN_NONE;
  167. for(Int i=start; i<=end; i++)
  168. {
  169. Token &token=*tokens[i];
  170. Int line = token.lineIndex();
  171. cline.includeLine(line);
  172. if(MustSeparate(last_type, token.type) || gcc && (token==TMPL_B || token==TMPL_E))cline.append(' ', TOKEN_NONE); // GCC does not handle << >> double templates
  173. last_type=token.type;
  174. token.asText(temp);
  175. FREPAD(t, temp)cline.cols.New().set(temp[t], token.col, line, i, token.type);
  176. }
  177. }
  178. }
  179. void Source::writeSymbolDecl(Memc<CodeLine> &clines, Symbol &symbol, Bool gcc)
  180. {
  181. Bool add_extern=(symbol.isVar() && !(symbol.modifiers&Symbol::MODIF_EXTERN));
  182. Int start =getSymbolStart(symbol.token_index),
  183. end =getListEnd (symbol.token_index);
  184. Token *token =symbol.getToken();
  185. // write full variable list until first ';' encountered
  186. if(symbol.fromPartialMacro()) // if this symbol was created from a partial macro, then we need to expand it fully (because macro can declare/define multiple variables, like DEFINE_CACHE, and when copying just DEFINE_CACHE into the header, we cannot insert the "extern" keyword inside it)
  187. {
  188. CodeLine &cl=clines.New();
  189. if(add_extern)cl.append("extern", TOKEN_KEYWORD).append(' ', TOKEN_NONE); // prepend by "extern"
  190. writeTokens(cl, start, end, gcc);
  191. }else
  192. {
  193. VecI2 var_start;
  194. write(clines, start, end, &var_start);
  195. if(add_extern && InRange(var_start.y, clines))clines[var_start.y].insert(var_start.x, ' ', TOKEN_NONE).insert(var_start.x, "extern", TOKEN_KEYWORD); // prepend by "extern"
  196. }
  197. // adjust tokens
  198. for(Int i=start; i<=end; i++)adjustToken(clines, i, gcc);
  199. }
  200. void Source::remove(Memc<CodeLine> &clines, Int start, Int end, Bool definite)
  201. {
  202. VecI2 s, e; if(destTokenRange(clines, start, end, s, e))Remove(clines, s, e, definite);
  203. }
  204. void Source::removeDefVal(Memc<CodeLine> &clines, Symbol &symbol)
  205. {
  206. if(symbol.isVar()) // only variables
  207. if(symbol.modifiers&Symbol::MODIF_DEF_VALUE)
  208. {
  209. Int start=symbol.def_val_range.x,
  210. end =symbol.def_val_range.y;
  211. if(InRange(start-1, tokens) && *tokens[start-1]=='=') // check if it's "=0" or "(0)" default value
  212. {
  213. start--;
  214. /*// we may have added 'f' suffix for float numbers "0.0 -> 0.0f" we need to catch it manually because 'remove' won't detect it (This was moved into 'Parse' because of issues with tokens generated from macros)
  215. if(InRange(end, tokens))
  216. {
  217. Token &token=*tokens[end];
  218. if(token.type==TOKEN_NUMBER)
  219. {
  220. Int col; if(CodeLine *cl=FindLineCol(clines, token.pos()+VecI2(token.length()-1, 0), col)) // get last character of token
  221. if((*cl)[col+1]=='f')cl->remove(col+1);
  222. }
  223. }*/
  224. }else{start--; end++;}
  225. remove(clines, start, end, true);
  226. }
  227. }
  228. Int Source::getSymbolStart(Int i) {return GetSymbolStart(tokens, i);}
  229. Int Source::getListEnd (Int i) // get next ';' marking end of var declaration
  230. {
  231. if(!InRange(i, tokens))return -1;
  232. for(; i<tokens.elms(); )if(*tokens[i++]==';')break;
  233. return i-1;
  234. }
  235. Int Source::getBodyStart(Int i)
  236. {
  237. if(!InRange(i, tokens))return -1;
  238. for(; i<tokens.elms(); i++)
  239. {
  240. Token &c=*tokens[i];
  241. if(c=='{' || c==';')break;
  242. }
  243. return i;
  244. }
  245. Int Source::getBodyEnd(Int i)
  246. {
  247. if(!InRange(i, tokens))return -1;
  248. for(Int level=0; i<tokens.elms(); i++)
  249. {
  250. Token &c=*tokens[i];
  251. if(c=='{') ++level;else
  252. if(c=='}')if(--level<=0)break;
  253. }
  254. if(InRange(i+1, tokens) && (*tokens[i+1])==';')i++;
  255. MIN(i, tokens.elms()-1);
  256. return i;
  257. }
  258. Bool Source::isFirstVar(Symbol &symbol)
  259. {
  260. if(!InRange(symbol.token_index, tokens))return false;
  261. for(Int i=symbol.token_index-1; i>=0; i--)
  262. {
  263. Token &c=*tokens[i];
  264. if(c=='(' || c=='*' || c=='&' || c=="const")continue; // ignore "int *const&(x)"
  265. if(c==',')return false;
  266. break;
  267. }
  268. return true;
  269. }
  270. CChar8* Source::adjustDot(Int i)
  271. {
  272. if(InRange(i, tokens))
  273. {
  274. Token &token=*tokens[i];
  275. if(token=='.')
  276. {
  277. Expr expr; Bool result=evaluateSymbol(i, expr); // we DO need to calculate from 'i' (and include the '.' separator) because expressions like "(TYPE*)obj." without the '.' separator would look like "(TYPE*)obj" and always return obj already casted to some type and be a pointer, which we don't want, we want the original "obj." first
  278. if(!result)return "::"; // if no expression was received then it means it was an empty "." command (which points to global namespace)
  279. // we have received an expression, so test it
  280. if( expr.instance && expr.symbol.isPtr())return "->"; // it's an instance and a pointer
  281. if(!expr.instance && expr.symbol )return "::"; // we have received symbol which is not an instance (it's a namespace or class)
  282. if( expr=="super" || expr=="__super" )return "::"; // super must be followed by "::" in C++
  283. // test for global namespace "5+.EE.SomeFunc()" or "(int).EE.SomeFunc()", in such cases we can receive operator '+' or ')' in both examples
  284. if(expr._operator && expr!=']' && expr!="++" && expr!="--" && expr!=')')return "::"; // x[]. is always '.', x<>. is always "::", x++. is always '.', x--. is always '.', x(). is usually a function call or operator() which use '.' or very frequently it's a cast "(int).EE.SomeFunc" which uses "::" (however because we've failed to fully compile, operator was received in the 'expr', we don't know for sure if it's a function call or cast, so we need to keep the '.' to allow usage of unknown symbols, so keep the original '.' and don't convert it into "::")
  285. }
  286. }
  287. return null;
  288. }
  289. void Source::adjustToken(Memc<CodeLine> &code_lines, Int i, Bool gcc)
  290. {
  291. if(InRange(i, tokens))
  292. {
  293. Token &token=*tokens[i];
  294. if(token=='.') // replace '.' with "->" or "::"
  295. {
  296. if(CChar8 *dot=adjustDot(i))
  297. {
  298. Int col; if(CodeLine *cl=FindLineCol(code_lines, token.pos(), col))cl->remove(col).insert(col, dot, TOKEN_OPERATOR, i);
  299. }
  300. }else
  301. /*if(token.type==TOKEN_NUMBER) // convert 0.0f -> 0.0f, 0.0 -> 0.0f, 0.0d -> 0.0 (This was moved into 'Parse' because of issues with tokens generated from macros)
  302. {
  303. FREPA(token)if(token[i]=='.') // if floating point
  304. {
  305. Char c=token.last(); Int col;
  306. if(c=='F' || c=='f'){}else // do nothing (0.0f -> 0.0f)
  307. if(CodeLine *cl=FindLineCol(code_lines, token.lineIndex(), token.col+token.length()-1, col)) // find column of last char of token
  308. {
  309. if(c=='d' || c=='D')cl->remove(col); // remove double suffix (0.0d -> 0.0 )
  310. else cl->insert(col+1, 'f', TOKEN_NUMBER); // add float suffix (0.0 -> 0.0f)
  311. }
  312. break;
  313. }
  314. }else*/
  315. if(gcc)
  316. {
  317. if(token==TMPL_E) // replace "Memc<Memc<TYPE>>" with "Memc<Memc<TYPE> >"
  318. {
  319. if(InRange(i+1, tokens))
  320. {
  321. Token &next=*tokens[i+1];
  322. if(next==TMPL_E && token.col+1==next.col && token.line==next.line)
  323. {
  324. Int col; if(CodeLine *cl=FindLineCol(code_lines, token.pos(), col))cl->insert(col+1, ' ', TOKEN_NONE);
  325. }
  326. }
  327. }else
  328. if(token==TMPL_B) // replace "Memc<::Class>" with "Memc< ::Class>" (this fails on Xcode 5 Apple LLVM compiler)
  329. {
  330. if(InRange(i+1, tokens))
  331. {
  332. Token &next=*tokens[i+1];
  333. if((next=='.' || next=="::") && token.col+1==next.col && token.line==next.line)
  334. {
  335. Int col; if(CodeLine *cl=FindLineCol(code_lines, token.pos(), col))cl->insert(col+1, ' ', TOKEN_NONE);
  336. }
  337. }
  338. }else
  339. if(token.type==TOKEN_KEYWORD && (token=="super" || token=="__super")) // replace 'super' with 'ClassName'
  340. {
  341. if(Symbol *symbol=finalSymbol(i+2)) // get 'symbol' from "super.symbol"
  342. if(Symbol *Class=symbol->Class())
  343. {
  344. Int col; if(CodeLine *cl=FindLineCol(code_lines, token.pos(), col))
  345. {
  346. remove(code_lines, i, i+1, true); // remove "super."
  347. Memc<Symbol::Modif> templates; if(token.parent)if(Symbol *Class=token.parent->Class())AddBaseTemplates(templates, *Class);
  348. writeClassPath(*cl, col, Class, null, true, &templates); // full class path must be written, because if writing only base name of the parent, then "class Obj : Game:Obj {void func() {super.func();}}" would translate into "Obj::func()" because both this and parent classes have the same name, error would occur
  349. }
  350. }
  351. }else
  352. if(token.type==TOKEN_KEYWORD && token=="friend") // replace "friend X;" with "friend struct X;"
  353. {
  354. if(InRange(i+1, tokens))
  355. if(tokens[i+1]->type!=TOKEN_KEYWORD) // quick check for skipping already correct "friend struct"
  356. for(Int j=i+1; j<tokens.elms(); j++)
  357. {
  358. Token &token=*tokens[j];
  359. if(token.type==TOKEN_OPERATOR)
  360. {
  361. if(token=='(' || token==')')break; // this is a function -> don't add keyword
  362. if(token==';' || token=='{' || token=='}') // encountered end of friend declaration
  363. {
  364. Token &token=*tokens[i+1];
  365. Bool is_class=false; // set false because 'class' is macro for 'struct' anyway in Esenthel Script
  366. //j=i+1; Str temp; Memc<Symbol::Modif> templates; Symbol *symbol=GetFullSymbol(tokens, j, temp, , templates);
  367. Int col; if(CodeLine *cl=FindLineCol(code_lines, token.pos(), col))cl->insert(col, ' ', TOKEN_NONE).insert(col, is_class ? "class" : "struct", TOKEN_KEYWORD);
  368. break;
  369. }
  370. }
  371. }
  372. }
  373. }
  374. }
  375. }
  376. void Source::writeClassPath(CodeLine &line, Int col, Symbol *parent, Symbol *cur_namespace, Bool global, Memc<Symbol::Modif> *templates, bool start_separator)
  377. {
  378. for(Symbol *cur=parent; cur && cur!=cur_namespace && (cur->type==Symbol::CLASS || cur->type==Symbol::NAMESPACE); cur=cur->Parent())
  379. {
  380. if(start_separator)line.insert(col, "::", TOKEN_OPERATOR);else start_separator=true;
  381. if(cur->templates.elms()) // write all templates of this symbol
  382. {
  383. line.insert(col, '>', TOKEN_OPERATOR);
  384. REPA(cur->templates)
  385. {
  386. if(i!=cur->templates.elms()-1)line.insert(col, ',', TOKEN_OPERATOR);
  387. Symbol *tmplt=cur->templates[i]();
  388. if(templates)REPA(*templates)if(Symbol::Modif &t=(*templates)[i])if(t.src_template==tmplt) // find known template target
  389. {
  390. writeClassPath(line, col, t(), null, true, &t.templates, false); // write itself, its templates, and its class path
  391. goto next; // we've already written it so don't write it manually below
  392. }
  393. if(tmplt)line.insert(col, *tmplt, TOKEN_CODE);
  394. next:;
  395. }
  396. line.insert(col, '<', TOKEN_OPERATOR);
  397. }
  398. line.insert(col, *cur, TOKEN_CODE);
  399. }
  400. if(global)line.insert(col, "::", TOKEN_OPERATOR); // start from global namespace
  401. }
  402. void Source::expandName(CodeLine &line, Int col, Symbol &symbol, Symbol *parent, Symbol *cur_namespace)
  403. {
  404. line.insert(col, symbol.cppName(), TOKEN_CODE); // name
  405. writeClassPath(line, col, parent, cur_namespace, false); // X<A,B>::Y::name
  406. }
  407. void Source::expandName(Memc<CodeLine> &code_lines, Symbol &symbol, Symbol *cur_namespace)
  408. {
  409. if(InRange(symbol.token_index, tokens))
  410. {
  411. Token &c=*tokens[symbol.token_index];
  412. if(c.type==TOKEN_KEYWORD && c=="operator")
  413. {
  414. VecI2 pos; if(FindLineCol(code_lines, c.pos(), pos))
  415. {
  416. writeClassPath(code_lines[pos.y], pos.x, symbol.Parent(), cur_namespace, false);
  417. }
  418. }else
  419. for(Int i=symbol.token_index; i<tokens.elms(); i++) // get symbol name ending
  420. {
  421. Token &e=*tokens[i];
  422. if(e=='(' || e==')' || e==',' || e=='=' || e==';' || e=='[') // "void func|(){}", "void (func)|(){}", "int x|,", "int x|(0)", "int x|=", "int x|;", "int x|[]=", "operator=", "operator()", ..
  423. {
  424. VecI2 start, end;
  425. if(FindLineCol(code_lines, c.pos(), start))
  426. if(FindLineCol(code_lines, e.pos(), end))
  427. {
  428. Remove(code_lines, start, end-VecI2(1, 0), true);
  429. expandName(code_lines[start.y], start.x, symbol, symbol.Parent(), cur_namespace);
  430. }
  431. break;
  432. }
  433. }
  434. }
  435. }
  436. void Source::expandRetVal(Memc<CodeLine> &code_lines, Symbol &symbol)
  437. {
  438. // if return value is a symbol (class/enum) defined inside another class, then we need to write "class path" to it
  439. if(symbol.value && symbol.value->type!=Symbol::TYPENAME) // TYPE func() does not need to be written
  440. if(Symbol *value_parent=symbol.value->Parent()) // if value type has parent
  441. if(value_parent->type==Symbol::CLASS) // if that parent is a class
  442. for(Int i=symbol.type_range.x; i<tokens.elms(); i++) // start parsing the "|TYPE method()" func definition to get the first symbol in the path to value
  443. {
  444. Token &t=*tokens[i]; Symbol *middle=t.symbol();
  445. if(!middle)break; // "::" operators can be ignored because they use full path already "::TYPE method()"
  446. if(!(middle->modifiers&Symbol::MODIF_CPP_MODIFIER)) // encountered 'const', 'virtual', .. (skip it and continue parsing)
  447. {
  448. if(Symbol *middle_parent=middle->Parent()) // if middle has parent
  449. {
  450. if(middle_parent->type==Symbol::CLASS) // if parent is a class then we need to write path from namespace to middle->parent
  451. {
  452. VecI2 pos; if(FindLineCol(code_lines, t.pos(), pos))writeClassPath(code_lines[pos.y], pos.x, middle_parent, null, true);
  453. }
  454. }else
  455. if(middle->type==Symbol::KEYWORD && *middle=="template") // skip template<..>
  456. {
  457. for(Int level=0; ++i<tokens.elms(); )
  458. {
  459. Token &t=*tokens[i];
  460. if(t==TMPL_B ) ++level;
  461. if(t==TMPL_E || t=='>')if(--level<=0)break;
  462. }
  463. continue;
  464. }
  465. break;
  466. }
  467. }
  468. }
  469. Bool Source::expandableTypename(Symbol &symbol)
  470. {
  471. if(symbol.type==Symbol::TYPENAME && InRange(symbol.token_index-1, tokens) && InRange(symbol.token_index, tokens))
  472. {
  473. Token &token=*tokens[symbol.token_index-1];
  474. return token!="typename" && token!="class" && token!="struct";
  475. }
  476. return false;
  477. }
  478. Bool Source::expandableTemplate(Int token_index)
  479. {
  480. if(InRange(token_index, tokens))
  481. {
  482. Token &token=*tokens[token_index];
  483. if(token==TMPL_B)
  484. {
  485. if(!InRange(token_index-1, tokens))return true;
  486. Token &prev=*tokens[token_index-1];
  487. if(prev=='{' || prev=='}' || prev==';' || prev=='>' || prev==TMPL_E)return true;
  488. }
  489. }
  490. return false;
  491. }
  492. void Source::expandTypename(Memc<CodeLine> &code_lines, Symbol &symbol, Int start_line)
  493. {
  494. if(expandableTypename(symbol))
  495. {
  496. Token &token=*tokens[symbol.token_index]; VecI2 pos=token.pos();
  497. for(Int y=start_line; y<code_lines.elms(); y++) // all lines need to be checked for multiple occurences
  498. if(code_lines[y].hasLine(pos.y))
  499. {
  500. CodeLine &line=code_lines[y]; Int col=line.findPos(pos); if(col>=0)line.insert(col, ' ', TOKEN_NONE).insert(col, "typename", TOKEN_KEYWORD);
  501. }
  502. }
  503. }
  504. void Source::expandTemplate(Memc<CodeLine> &code_lines, Int token_index, Int start_line)
  505. {
  506. if(expandableTemplate(token_index))
  507. {
  508. Token &token=*tokens[token_index]; VecI2 pos=token.pos();
  509. for(Int y=start_line; y<code_lines.elms(); y++) // all lines need to be checked for multiple occurences
  510. if(code_lines[y].hasLine(pos.y))
  511. {
  512. CodeLine &line=code_lines[y]; Int col=line.findPos(pos); if(col>=0)line.insert(col, "template", TOKEN_KEYWORD);
  513. }
  514. }
  515. }
  516. void Source::expandTemplates(Memc<CodeLine> &code_lines)
  517. {
  518. REPA(symbols)expandTypename(code_lines, *symbols[i]);
  519. REPA(tokens )expandTemplate(code_lines, i );
  520. }
  521. void Source::writeClassTemplates(Memc<CodeLine> &clines, Symbol *Class)
  522. {
  523. Memc<Symbol*> template_classes; for(; Class && Class->type==Symbol::CLASS; Class=Class->Parent())if(Class->templates.elms())template_classes.add(Class);
  524. REPA(template_classes){Symbol *Class=template_classes[i]; write(clines, getSymbolStart(Class->token_index), Class->token_index-2);} // skip "struct name"
  525. }
  526. void Source::writeCtorInit(Memc<CodeLine> &clines, Symbol &ci, Int &line_i, Bool first, Bool gcc)
  527. {
  528. CodeLine &line=clines[line_i];
  529. if(first)line.append(' ', TOKEN_NONE ).append(':', TOKEN_OPERATOR).append(' ', TOKEN_NONE);
  530. else line.append(',', TOKEN_OPERATOR).append(' ', TOKEN_NONE);
  531. // -1 to include ('=' or '(') in "x=5;", +1 to include (')' or ',' or ';') in "x=5;"
  532. // this extra space will also copy any preprocessor between the symbol, default value and the end, like this:
  533. // x=
  534. // #if 1
  535. // 5
  536. // #else
  537. // 0
  538. // #endif
  539. // ;
  540. // watch out for "void (*func)(ptr)=null;"
  541. write(clines, ci.token_index , ci.token_index , null, &line_i); // write 'symbol.name'
  542. write(clines, ci.def_val_range.x-1, ci.def_val_range.y+1, null, &line_i); // write default value
  543. if(Token *equals=getToken(ci.def_val_range.x-1)) // get '=' token
  544. {
  545. Int col; if(CodeLine *cl=FindLineCol(clines, equals->pos(), col))cl->cols[col].c='('; // replace it with '('
  546. }
  547. if(Token *end=getToken(ci.def_val_range.y+1)) // get ';' token
  548. {
  549. Int col; if(CodeLine *cl=FindLineCol(clines, end->pos(), col))cl->cols[col].c=')'; // replace it with ')'
  550. }
  551. for(Int i=ci.def_val_range.x; i<=ci.def_val_range.y; i++)adjustToken(clines, i, gcc);
  552. }
  553. void Source::writeCtorInits(Memc<CodeLine> &clines, Symbol &func, Int body_start, Bool gcc)
  554. {
  555. if((func.modifiers&Symbol::MODIF_CTOR) && InRange(body_start-1, tokens)) // if is constructor
  556. if(Symbol *Class=func.Class())
  557. if(Class->ctor_inits.elms()) // don't try to skip if "func.ctor_inits.elms()==Class->ctor_inits.elms()" because these may be different members
  558. {
  559. Token &token=*tokens[body_start-1];
  560. VecI2 pos; if(FindLineCol(clines, token.pos(), pos))
  561. {
  562. pos.x++;
  563. CodeLine *cl=&clines[pos.y]; VecI2 start_lines=cl->lines;
  564. MemtN<CodeCol, 64> end; for(Int i=pos.x; i<cl->cols.elms(); i++)end.add(cl->cols[i]); cl->cols.setNum(pos.x); // remove all end of line to temporary container, because 'writeCtorInit' can operate only by appending
  565. Bool first=!func.ctor_inits.elms(); // if none were listed yet
  566. if(first) // there is a possibility that there's a ctor init for the base class "class Base{Base(Obj *){}} class Ext : Base{Ext(Obj *obj):Base(obj){}}"
  567. for(Int i=body_start-1, level=0; i>=func.token_index; i--) // check all tokens from declaration start to end for existence of ':' token in the main level (to avoid something like "Ext(Obj *obj=0?null:null)" or anything else)
  568. {
  569. Token &token=*tokens[i];
  570. if(token=='(')level++;else
  571. if(token==')')level--;else
  572. if(token==':' && level==0){first=false; break;}
  573. }
  574. FREPA(Class->ctor_inits) // all required
  575. {
  576. SymbolPtr &ci=Class->ctor_inits[i]; if(!func.ctor_inits.has(ci)) // if not yet listed
  577. if(ci->source)
  578. {
  579. // we need to use the source where the class member is listed, and not this source where the function is listed
  580. // for example Source A: "class A{int x=0; A();}", Source B: "A::A(){}"
  581. // this is Source B with the function definition, however class member is listed in Source A
  582. ci->source->writeCtorInit(clines, *ci, pos.y, first, gcc); // write
  583. first=false;
  584. }
  585. }
  586. if(end.elms()) // if we need to insert columns
  587. {
  588. cl=&clines[pos.y]; // get current line, access it again because 'pos.y' could've changed
  589. if(!cl->hasAnyLines(start_lines))cl=&clines.NewAt(++pos.y).includeLines(start_lines); // create new line if needed
  590. FREPA(end)cl->cols.add(end[i]); // append previously removed columns
  591. }
  592. }
  593. }
  594. }
  595. void Source::writeForcedCtor(Memc<CodeLine> &clines, Symbol &Class, Symbol* &Namespace, Bool gcc)
  596. {
  597. AdjustNameSymbol(clines, Namespace, Class.Namespace());
  598. writeClassTemplates(clines, &Class);
  599. {
  600. CodeLine &line=clines.New();
  601. REP(Namespace ? (Namespace->level+1)*TabLength : 0)line.append(' ', TOKEN_NONE);
  602. expandName(line, line.cols.elms(), Class, &Class, Namespace); // X::X
  603. line.append("()", TOKEN_OPERATOR); // X::X()
  604. } // braces so that we won't use 'line' after 'writeCtorInit' because that may change its address
  605. Int line_i=clines.elms()-1;
  606. FREPA(Class.ctor_inits)writeCtorInit(clines, *Class.ctor_inits[i], line_i, i==0, gcc); // X::X() x(..)
  607. clines.last().append(' ', TOKEN_NONE).append("{}", TOKEN_OPERATOR); // X::X() x(..) {}
  608. clines.New();
  609. }
  610. /******************************************************************************/
  611. void Source::detectDefaultCtors()
  612. {
  613. // detect if classes need default constructors
  614. FREPA(symbols){Symbol &symbol=*symbols[i]; if(symbol.type!=Symbol::FUNC)symbol.ctor_inits.clear(); FlagDisable(symbol.helper, Symbol::HELPER_FORCE_CTOR);}
  615. FREPA(symbols) // order important to add 'ctor_inits' as they are listed in the class
  616. {
  617. Symbol &symbol=*symbols[i];
  618. if(symbol.isVar() && (symbol.modifiers&Symbol::MODIF_DEF_VALUE) && !(symbol.modifiers&Symbol::MODIF_STATIC) && symbol.Parent() && symbol.Parent()->type==Symbol::CLASS) // class non-static members with default values
  619. {
  620. Symbol &Class=*symbol.Parent();
  621. if(!Class.ctor_inits.elms()) // if we're adding first initializer, check if it needs forced constructor
  622. {
  623. if(Symbol *ctors=FindChild(Class, &Class, null, false)()) // check if has any ctors
  624. REPA(ctors->funcs)
  625. {
  626. Symbol &ctor=*ctors->funcs[i];
  627. if(!ctor.params.elms() || (ctor.params[0]->modifiers&Symbol::MODIF_DEF_VALUE))goto has_default_ctor;
  628. }
  629. Class.helper|=Symbol::HELPER_FORCE_CTOR; // if not found then force default constructor
  630. has_default_ctor:;
  631. }
  632. Class.ctor_inits.add(&symbol); // add to the list of required initializers (after checking for forced constructor)
  633. }
  634. }
  635. // check if we have to disable forced constructors (if some member is a reference without a default value)
  636. REPA(symbols)
  637. {
  638. Symbol &symbol=*symbols[i];
  639. if(symbol.isVar() && (symbol.value.modifiers&Symbol::MODIF_REF) && !(symbol.modifiers&Symbol::MODIF_DEF_VALUE) && !(symbol.modifiers&Symbol::MODIF_STATIC) && symbol.Parent()/* && symbol.Parent()->type==Symbol::CLASS check not needed because we just disable HELPER_FORCE_CTOR*/) // class non-static reference member without default value
  640. {
  641. Symbol &Class=*symbol.Parent();
  642. FlagDisable(Class.helper, Symbol::HELPER_FORCE_CTOR); // can't do forced constructor
  643. }
  644. }
  645. }
  646. /******************************************************************************/
  647. Bool Source::writeClass(Memc<CodeLine> &clines, Symbol &symbol, Bool gcc)
  648. {
  649. if(symbol.type==Symbol::CLASS && symbol.isGlobal()) // global classes only
  650. {
  651. symbol.helper|=Symbol::HELPER_PROCESSED|Symbol::HELPER_PROCESSED_FULL;
  652. Int start =getSymbolStart(symbol.token_index),
  653. end =getBodyEnd (start); if(symbol.modifiers&Symbol::MODIF_TYPEDEF)end=getListEnd(end); // if class was defined with typedef "typedef class .. { } .. ;" then after '}' it is followed by typedefs until;
  654. if(InRange(start, tokens))
  655. {
  656. Memc<Symbol*> namespaces; for(Symbol *name=symbol.Parent(); name && name->type==Symbol::NAMESPACE; name=name->Parent())namespaces.NewAt(0)=name;
  657. // start namespaces
  658. clines.New().append(SEP_LINE, TOKEN_COMMENT);
  659. FREPA(namespaces)clines.New().append("namespace", TOKEN_KEYWORD).append(' ', TOKEN_NONE).append(*namespaces[i], TOKEN_CODE).append('{', TOKEN_OPERATOR);
  660. if(namespaces.elms())clines.New().append(SEP_LINE, TOKEN_COMMENT);
  661. // copy comments located before the class
  662. Token &start_token=*tokens[start];
  663. VecI2 start_com(-1), end_com(-1), pos_com(start_token.col-1, start_token.lineIndex());
  664. for(; lineValid(pos_com); dec(pos_com))
  665. {
  666. TOKEN_TYPE type=lines[pos_com.y].Type(pos_com.x);
  667. if(type==TOKEN_COMMENT)
  668. {
  669. if(end_com.x<0)end_com=pos_com;
  670. start_com=pos_com;
  671. }else
  672. if(ValidType(type))break; // encountered char which is a token
  673. }
  674. if(start_com.x>=0)write(clines, start_com, end_com);
  675. // write class
  676. write(clines, start, end);
  677. // remove function bodies
  678. // insert ';' at the end of struct/class/enum declarations
  679. // convert '.' to "->" or "::" when needed
  680. for(Int i=start; i<=end; i++)
  681. {
  682. Token &c=*tokens[i]; adjustToken(clines, i, gcc);
  683. if(c=='}' && c.parent)if(c.parent->type==Symbol::CLASS || c.parent->type==Symbol::ENUM)
  684. {
  685. VecI2 pos; if(FindLineCol(clines, c.pos(), pos))
  686. {
  687. CodeLine &cl=clines[pos.y];
  688. // put ';'
  689. if(!(c.parent->modifiers&Symbol::MODIF_TYPEDEF)) // don't write ';' if the class was defined with typedef "typedef class .. {} .. ;" because in that case the codes need to be followed by ';'
  690. if(!InRange(i+1, tokens) || (*tokens[i+1])!=';') // only if it's not already there (this caused issues when the struct/class/enum was defined by a macro, like UNION)
  691. cl.insert(pos.x+1, ';', TOKEN_OPERATOR); // apend '}' with ';'
  692. if(c.parent->helper&Symbol::HELPER_FORCE_CTOR) // force default constructor
  693. {
  694. REP(pos.x-1)if(cl.cols[i].type!=TOKEN_NONE) // there is something before '}'
  695. {
  696. cl.insert(pos.x, "();", TOKEN_OPERATOR).insert(pos.x, *c.parent, TOKEN_CODE).insert(pos.x, ' ', TOKEN_NONE).insert(pos.x, ':', TOKEN_OPERATOR).insert(pos.x, "public", TOKEN_KEYWORD).insert(pos.x, ' ', TOKEN_NONE); // public: X();
  697. goto added_ctor;
  698. }
  699. {
  700. // TODO: align columns to level
  701. CodeLine &cl=clines.NewAt(pos.y); REP(TabLength)cl.append(' ', TOKEN_NONE); cl.append(*c.parent, TOKEN_CODE).append("();", TOKEN_OPERATOR); // X();
  702. clines.NewAt(pos.y).append("public", TOKEN_KEYWORD).append(':', TOKEN_OPERATOR); // public:
  703. clines.NewAt(pos.y);
  704. }
  705. added_ctor:;
  706. }
  707. }
  708. }
  709. if(c=='{' && c.parent && c.parent->type==Symbol::FUNC // function bodies
  710. || c==':' && c.ctor_initializer) // optionally started with constructor initializers
  711. {
  712. VecI2 func, from, to;
  713. if(InRange(i-1, tokens))
  714. if(FindLineCol(clines, tokens[i-1]->pos(), func))
  715. if(FindLineCol(clines, c .pos(), from))
  716. for(Int level=0; i<=end; i++)
  717. {
  718. Token &c=*tokens[i];
  719. if(c=='{') ++level;else
  720. if(c=='}')if(--level<=0)
  721. {
  722. if(FindLineCol(clines, c.pos(), to))
  723. {
  724. Remove(clines, from, to, false); // remove function body
  725. CodeLine &cl=clines[func.y];
  726. for(; InRange(func.x, cl) && TokenType(cl.cols[func.x].type); func.x++); // skip last token before function body, typically ')', but can be "const final override .."
  727. if ( InRange(func.x, cl) && cl.cols[func.x].c==' ' && cl.type(func.x+1)!=TOKEN_COMMENT)cl.cols[func.x].set(';', -1, -1, -1, TOKEN_OPERATOR);else cl.insert(func.x, ';', TOKEN_OPERATOR); // end func declaration with ';', replace existing ' ' but not if it's followed by a comment (to keep "); //")
  728. }
  729. break;
  730. }
  731. }
  732. }
  733. }
  734. // close namespaces
  735. clines.New().append(SEP_LINE, TOKEN_COMMENT);
  736. FREPA(namespaces)clines.New().append('}', TOKEN_OPERATOR).append(' ', TOKEN_NONE).append(S+"// namespace "+*namespaces[i], TOKEN_COMMENT);
  737. if(namespaces.elms())clines.New().append(SEP_LINE, TOKEN_COMMENT);
  738. Symbol *Namespace=null;
  739. // write global typedefs for this class
  740. #if WRITE_SEPARATORS
  741. clines.New().append("// TYPEDEFS", TOKEN_COMMENT);
  742. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  743. #endif
  744. FREPA(Symbols)
  745. {
  746. Symbol &Typedef=Symbols.lockedData(i);
  747. if(!(Typedef.helper&Symbol::HELPER_PROCESSED))
  748. if(Typedef.type==Symbol::TYPEDEF && Typedef.source && Typedef.valid && Typedef.value && Typedef.value->valid && Typedef.isGlobal()) // process only global typedefs
  749. if(Symbol *root=Typedef.value->rootClass())
  750. if(root->helper&Symbol::HELPER_PROCESSED_FULL) // only if root class of target is processed
  751. {
  752. Typedef.helper|=Symbol::HELPER_PROCESSED|Symbol::HELPER_PROCESSED_FULL;
  753. Source &source=*Typedef.source;
  754. if( source.isFirstVar(Typedef)) // process only first typedef
  755. {
  756. // adjust namespaces to typedef namespace
  757. AdjustNameSymbol(clines, Namespace, Typedef.Namespace());
  758. source.writeSymbolDecl(clines, Typedef, gcc);
  759. }
  760. }
  761. }
  762. // adjust namespaces to global namespace
  763. AdjustNameSymbol(clines, Namespace, null);
  764. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  765. // write global variables of this class type
  766. #if WRITE_SEPARATORS
  767. clines.New().append("// VARIABLES", TOKEN_COMMENT);
  768. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  769. #endif
  770. FREPA(symbols)
  771. {
  772. Symbol &var=*symbols[i];
  773. if(var.isGlobal() && var.isVar() && isFirstVar(var) && !var.constDefineInHeader() && !(var.helper&Symbol::HELPER_PROCESSED) // process only global and first variables on the list
  774. && var.value && var.value->rootClass()==&symbol) // type of the value is the class being processed
  775. {
  776. var.helper|=Symbol::HELPER_PROCESSED;
  777. // adjust namespaces to variable namespace
  778. AdjustNameSymbol(clines, Namespace, var.Namespace());
  779. writeSymbolDecl(clines, var, gcc);
  780. }
  781. }
  782. // adjust namespaces to global namespace
  783. AdjustNameSymbol(clines, Namespace, null);
  784. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  785. // clean 'TOKEN_REMOVE'
  786. Clean(clines);
  787. // remove starting symbols
  788. REP(tokens[start]->col)
  789. {
  790. REPA (clines)if(clines[i].cols.elms() && ValidType(clines[i].cols[0].type))goto finished_start_spaces;
  791. REPAO(clines).remove(0);
  792. }
  793. finished_start_spaces:;
  794. // remove default variable values "x={..}" and "x(..)"
  795. FREPA(symbols)
  796. {
  797. Symbol &symbol=*symbols[i];
  798. if(symbol.Parent() && symbol.Parent()->type==Symbol::CLASS // only class vars
  799. || symbol.isGlobal()) // or global variables
  800. removeDefVal(clines, symbol);
  801. }
  802. // fix templates <TYPE> -> template<typename TYPE>
  803. FREPA(symbols)expandTypename(clines, *symbols[i]);
  804. FREPA(tokens )expandTemplate(clines, i );
  805. Parse(clines);
  806. return true;
  807. }
  808. }
  809. return false;
  810. }
  811. /******************************************************************************/
  812. Bool Source::writeVarFuncs(Memc<CodeLine> &clines, Bool gcc)
  813. {
  814. Bool is=false; // if actually contains anything
  815. Symbol *Namespace=null;
  816. // write global variables forward declarations (skip default values)
  817. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  818. #if WRITE_SEPARATORS
  819. clines.New().append("// VARIABLES", TOKEN_COMMENT);
  820. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  821. #endif
  822. FREPA(symbols)
  823. {
  824. Symbol &symbol=*symbols[i];
  825. if(symbol.isGlobal() && symbol.isVar() && isFirstVar(symbol) && !symbol.constDefineInHeader() && !(symbol.helper&Symbol::HELPER_PROCESSED)) // process only global and first variables on the list
  826. {
  827. is=true;
  828. symbol.helper|=Symbol::HELPER_PROCESSED;
  829. // adjust namespaces to variable namespace
  830. AdjustNameSymbol(clines, Namespace, symbol.Namespace());
  831. writeSymbolDecl(clines, symbol, gcc);
  832. }
  833. }
  834. // remove default variable values "x={..}" and "x(..)"
  835. FREPA(symbols)
  836. {
  837. Symbol &symbol=*symbols[i];
  838. if(symbol.isGlobal()) // only global vars
  839. removeDefVal(clines, symbol);
  840. }
  841. // adjust namespaces to global namespace
  842. AdjustNameSymbol(clines, Namespace, null);
  843. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  844. #if WRITE_SEPARATORS
  845. clines.New().append("// FUNCTIONS", TOKEN_COMMENT);
  846. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  847. #endif
  848. // write global functions forward declarations (without bodies)
  849. FREPA(symbols)
  850. {
  851. Symbol &symbol=*symbols[i];
  852. if(symbol.isGlobalFunc() && InRange(symbol.token_index, tokens) && !(symbol.modifiers&Symbol::MODIF_FRIEND)) // friend functions should be listed only inside classes
  853. {
  854. is=true;
  855. // adjust namespaces to function namespace
  856. AdjustNameSymbol(clines, Namespace, symbol.Namespace());
  857. Int start=getSymbolStart(symbol.token_index) , // get func declaration start
  858. end=getBodyStart (symbol.token_index)-1; // get func declaration end
  859. write(clines, start, end);
  860. if(clines.elms())clines.last().append(';', TOKEN_OPERATOR);
  861. // adjust tokens
  862. for(Int i=start; i<=end; i++)adjustToken(clines, i, gcc);
  863. }
  864. }
  865. if(is)
  866. {
  867. // expand templates
  868. expandTemplates(clines);
  869. // adjust namespaces to global namespace
  870. AdjustNameSymbol(clines, Namespace, null);
  871. clines.New().append(SEP_LINE, TOKEN_COMMENT);
  872. // clean
  873. Clean(clines);
  874. Parse(clines);
  875. }
  876. return is;
  877. }
  878. /******************************************************************************/
  879. Bool Source::writeFunc(Memc<CodeLine> &clines, Bool gcc, Symbol &symbol, Symbol* &Namespace)
  880. {
  881. if((symbol.modifiers&Symbol::MODIF_FUNC_BODY) && !symbol.insideFunc()) // process only functions with bodies
  882. {
  883. Int start=getSymbolStart(symbol.token_index); if(InRange(start, tokens))
  884. {
  885. Int body_start=getBodyStart(symbol.token_index), // get func declaration end
  886. end =getBodyEnd (body_start);
  887. // parse function to obtain info about local vars
  888. parseFunc(symbol);
  889. Bool is_inline=symbol.isInlineFunc(), write=true;
  890. if(!is_inline) // inline functions are written to headers, and always need to be written, as for non-inline, check that
  891. {
  892. Token &c=*tokens[start],
  893. &e=*tokens[ end];
  894. VecI2 temp;
  895. if(FindLineCol(clines, c.pos(), temp)
  896. && FindLineCol(clines, e.pos(), temp))write=false; // if the body already exists, then don't write it
  897. }
  898. if(write)
  899. {
  900. AdjustNameSymbol(clines, Namespace, symbol.Namespace());
  901. // write class templates list
  902. if(symbol.insideClass()) // only if func body was declared inside class, and now we need to store the body outside of it (if it was already stored outside class then it has class templates listed already)
  903. writeClassTemplates(clines, symbol.Parent());
  904. // write the body
  905. T.write(clines, start, end);
  906. // remove function modifiers for body declarations (virtual, static, ..) before expanding names and return value (so that removing modifier along with the FullPath will not happen "virtual TYPE name" -> "virtual FullPath::TYPE name" -> "TYPE name")
  907. for(Int i=start; i<symbol.token_index; i++)
  908. {
  909. Token &mod=*tokens[i];
  910. if(mod.symbol && (mod.symbol->modifiers&Symbol::MODIF_CPP_MODIFIER) && mod!="const")
  911. {
  912. Token &next=*tokens[i+1];
  913. VecI2 start, end;
  914. if(FindLineCol(clines, mod .pos(), start))
  915. if(FindLineCol(clines, next.pos(), end))Remove(clines, start, end-VecI2(1, 0), true);
  916. }
  917. }
  918. // remove function modifiers for body declarations (final, override)
  919. for(Int i=body_start-1; i>symbol.token_index; i++)
  920. {
  921. Token &mod=*tokens[i]; if(mod.symbol && (mod.symbol->modifiers&Symbol::MODIF_CPP_MODIFIER))
  922. {
  923. if(mod!="const")
  924. {
  925. Token &next=*tokens[i+1];
  926. VecI2 start, end;
  927. if(FindLineCol(clines, mod .pos(), start))
  928. if(FindLineCol(clines, next.pos(), end))Remove(clines, start, end-VecI2(1, 0), true);
  929. }
  930. }else break; // stop on func()|override
  931. }
  932. // replace name with full name
  933. expandName(clines, symbol, Namespace);
  934. // expand return value name
  935. expandRetVal(clines, symbol);
  936. }
  937. // remove default values in function params list
  938. REPA(symbol.params)removeDefVal(clines, *symbol.params[i]);
  939. // write ctor initializers
  940. writeCtorInits(clines, symbol, body_start, gcc);
  941. // adjust token
  942. for(Int i=start; i<end; i++)adjustToken(clines, i, gcc);
  943. return true;
  944. }
  945. }
  946. return false;
  947. }
  948. Bool Source::writeStaticVars(Memc<CodeLine> &clines, Bool gcc, Symbol* &Namespace, Bool templates)
  949. {
  950. Bool is=false;
  951. FREPA(symbols)
  952. {
  953. Symbol &symbol=*symbols[i];
  954. if(symbol.isVar() && symbol.Parent() && symbol.Parent()->type==Symbol::CLASS && (symbol.modifiers&Symbol::MODIF_STATIC) && symbol.insideTemplateClass()==templates) // only static class vars
  955. if(InRange(symbol.token_index, tokens))
  956. {
  957. Bool first=true;
  958. for(Int i=symbol.token_index-1; i>=0; i--)
  959. {
  960. Token &c=*tokens[i];
  961. if(c=='(' || c=='*' || c=='&')continue; // ignore "int *&(x)"
  962. if(c==',')first=false;
  963. break;
  964. }
  965. if(first) // process only first variables on the list
  966. {
  967. is=true;
  968. Int start=getSymbolStart(symbol.token_index),
  969. end =getListEnd (symbol.token_index);
  970. // write full variable list until first ';' encountered
  971. Int var_start=clines.elms();
  972. AdjustNameSymbol(clines, Namespace, symbol.Namespace());
  973. writeClassTemplates(clines, symbol.Parent());
  974. write(clines, start, end);
  975. // remove var modifiers
  976. for(Int i=start; i<symbol.token_index; i++)
  977. {
  978. Token &mod=*tokens[i];
  979. if( mod.symbol && (mod.symbol->modifiers&Symbol::MODIF_CPP_MODIFIER) && mod=="static") // only static modifier can be removed
  980. {
  981. Token &next=*tokens[i+1];
  982. VecI2 start, end;
  983. if(FindLineCol(clines, mod .pos(), start))
  984. if(FindLineCol(clines, next.pos(), end))Remove(clines, start, end-VecI2(1, 0), true);
  985. }
  986. }
  987. // expand value type name
  988. expandRetVal(clines, symbol);
  989. // adjust token
  990. for(Int i=start; i<end; i++)adjustToken(clines, i, gcc);
  991. }
  992. }
  993. }
  994. if(is)FREPA(symbols) // expand full names of written variables, do this after writing because statics could be written using lists (many at one time)
  995. {
  996. Symbol &symbol=*symbols[i];
  997. if(symbol.isVar() && symbol.Parent() && symbol.Parent()->type==Symbol::CLASS && (symbol.modifiers&Symbol::MODIF_STATIC) && symbol.insideTemplateClass()==templates) // only static class vars
  998. expandName(clines, symbol, symbol.Namespace());
  999. }
  1000. return is;
  1001. }
  1002. /******************************************************************************/
  1003. Bool Source::writeInline(Memc<CodeLine> &clines, Bool gcc)
  1004. {
  1005. Bool is=false; // if actually contains anything
  1006. Symbol *Namespace=null;
  1007. clines.New().append(SEP_LINE, TOKEN_COMMENT);
  1008. // insert static class vars
  1009. is|=writeStaticVars(clines, gcc, Namespace, true);
  1010. // insert class method bodies
  1011. FREPA(symbols)
  1012. {
  1013. Symbol &symbol=*symbols[i];
  1014. if(symbol.isInlineFunc())is|=writeFunc(clines, gcc, symbol, Namespace);
  1015. }
  1016. // write forced constructors
  1017. FREPA(symbols)
  1018. {
  1019. Symbol &symbol=*symbols[i];
  1020. if((symbol.helper&Symbol::HELPER_FORCE_CTOR) && symbol.isTemplateClass()){is=true; writeForcedCtor(clines, symbol, Namespace, gcc);}
  1021. }
  1022. if(is)
  1023. {
  1024. // expand templates
  1025. expandTemplates(clines);
  1026. // adjust namespaces to global namespace
  1027. AdjustNameSymbol(clines, Namespace, null);
  1028. clines.New().append(SEP_LINE, TOKEN_COMMENT);
  1029. Parse(clines);
  1030. }
  1031. return is;
  1032. }
  1033. void Source::makeCPP(C Str &path, C Str &file, Bool gcc, Bool include_headers)
  1034. {
  1035. Memc<CodeLine> clines;
  1036. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  1037. clines.New().append("#include", TOKEN_PREPROC).append(' ', TOKEN_NONE).append( "\"stdafx.h\"" , TOKEN_TEXT8);
  1038. if(include_headers)clines.New().append("#include", TOKEN_PREPROC).append(' ', TOKEN_NONE).append(S+"\""+UnixPath(GetRelativePath(GetPath(file), path+UNIQUE_NAME+UNIQUE_NAME+"headers.h"))+"\"", TOKEN_TEXT8);
  1039. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  1040. if(lines.elms())write(clines, VecI2(0, 0), VecI2(lines.last().length()-1, lines.elms()-1));
  1041. // remove stuff
  1042. REPA(symbols)
  1043. {
  1044. Symbol &symbol=*symbols[i];
  1045. if(symbol.type==Symbol::CLASS && symbol.isGlobal() // all global classes
  1046. || symbol.type==Symbol::ENUM && symbol.isGlobal() // all global enums
  1047. || symbol.isInlineFunc()) // all inline functions
  1048. {
  1049. Int start=getSymbolStart(symbol.token_index),
  1050. end =getBodyEnd (start);
  1051. remove(clines, start, end, false);
  1052. }else
  1053. if(symbol.isGlobalFunc() && !symbol.templates.elms() && !(symbol.modifiers&Symbol::MODIF_FUNC_BODY) // all global function declarations
  1054. || symbol.isVar() && ((symbol.modifiers&Symbol::MODIF_EXTERN) || symbol.isGlobal() && symbol.constDefineInHeader())) // all externs and global simple constants
  1055. {
  1056. Int start=getSymbolStart(symbol.token_index),
  1057. end =getListEnd (start);
  1058. remove(clines, start, end, false);
  1059. }else
  1060. if(symbol.type==Symbol::TYPEDEF && symbol.isGlobal()) // all global typedef lists
  1061. {
  1062. Int start=getSymbolStart(symbol.token_index),
  1063. end =getListEnd (start);
  1064. if(symbol.fromPartialMacro()) // if this symbol was created from a partial macro, then we have to keep it as the macro may also define other things, like 'DEFINE_CACHE' that also defines variables
  1065. {
  1066. // since we're keeping it then we need to adjust tokens
  1067. for(Int i=start; i<end; i++)adjustToken(clines, i, gcc);
  1068. }else // otherwise we can remove it as it will be stored in the headers
  1069. {
  1070. remove(clines, start, end, false);
  1071. }
  1072. }
  1073. }
  1074. // clean
  1075. Clean(clines);
  1076. clines.New().append(SEP_LINE, TOKEN_COMMENT);
  1077. // adjust global variables
  1078. FREPA(symbols)
  1079. {
  1080. Symbol &symbol=*symbols[i];
  1081. if(symbol.isGlobal() && symbol.isVar() && isFirstVar(symbol)) // process only global and first variables on the list
  1082. {
  1083. Int start=getSymbolStart(symbol.token_index),
  1084. end =getListEnd (symbol.token_index);
  1085. // adjust token
  1086. for(Int i=start; i<end; i++)adjustToken(clines, i, gcc);
  1087. }
  1088. }
  1089. // adjust global functions
  1090. FREPA(symbols)
  1091. {
  1092. Symbol &symbol=*symbols[i];
  1093. if(symbol.isGlobalFunc() && !symbol.templates.elms() && (symbol.modifiers&Symbol::MODIF_FUNC_BODY)) // process only global functions
  1094. {
  1095. Int start=getSymbolStart(symbol.token_index),
  1096. end =getBodyEnd (start);
  1097. if(InRange(start, tokens))
  1098. {
  1099. // parse function to obtain info about local vars
  1100. parseFunc(symbol);
  1101. // remove default values in function params list
  1102. REPA(symbol.params)removeDefVal(clines, *symbol.params[i]);
  1103. // adjust token
  1104. for(Int i=start; i<end; i++)adjustToken(clines, i, gcc);
  1105. }
  1106. }
  1107. }
  1108. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  1109. #if WRITE_SEPARATORS
  1110. clines.New().append("// CLASS STATIC MEMBERS", TOKEN_COMMENT);
  1111. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  1112. #endif
  1113. Symbol *Namespace=null;
  1114. // insert static class vars
  1115. writeStaticVars(clines, gcc, Namespace, false);
  1116. AdjustNameSymbol(clines, Namespace, null);
  1117. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  1118. #if WRITE_SEPARATORS
  1119. clines.New().append("// CLASS METHODS", TOKEN_COMMENT);
  1120. clines.New().append(SEP_LINE , TOKEN_COMMENT);
  1121. #endif
  1122. // TODO: align start spaces to namespace level (make func for that, that removes/adds first columns)
  1123. // insert class method bodies
  1124. FREPA(symbols)
  1125. {
  1126. Symbol &symbol=*symbols[i];
  1127. if((symbol.isFunc() && symbol.Parent() && symbol.Parent()->type==Symbol::CLASS) || (symbol.type==Symbol::FUNC && (symbol.modifiers&Symbol::MODIF_FRIEND))) // friend functions also need to be written
  1128. if(!symbol.isInlineFunc())writeFunc(clines, gcc, symbol, Namespace);
  1129. }
  1130. // write forced constructors
  1131. FREPA(symbols)
  1132. {
  1133. Symbol &symbol=*symbols[i];
  1134. if((symbol.helper&Symbol::HELPER_FORCE_CTOR) && !symbol.isTemplateClass())writeForcedCtor(clines, symbol, Namespace, gcc);
  1135. }
  1136. AdjustNameSymbol(clines, Namespace, null);
  1137. clines.New().append(SEP_LINE, TOKEN_COMMENT);
  1138. // remove double separators
  1139. REPA(clines)if(i && clines[i]==SEP_LINE && clines[i-1]==SEP_LINE)clines.remove(i, true);
  1140. // write file
  1141. FCreateDirs(GetPath(file));
  1142. Parse(clines);
  1143. if(OverwriteOnChangeLoud(clines, file))
  1144. if(LineMap *lm=CE.build_line_maps.get(file))lm->add(loc, clines);
  1145. //if(loc!=Str(AutoSource))FTimeUTC(file, modify_time); // don't adjust file modification time for auto header, just rely on overwrite on change, currently commented out, is there any point in this since above there's overwrite on change?
  1146. }
  1147. /******************************************************************************/
  1148. }}
  1149. /******************************************************************************/