CE Symbol.cpp 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Edit{
  5. /******************************************************************************/
  6. Int EnumSize=4, // 4 bytes
  7. #if X64
  8. PtrSize=8; // 8 bytes (64-bits)
  9. #else
  10. PtrSize=4; // 4 bytes (32-bits)
  11. #endif
  12. /******************************************************************************/
  13. DEFINE_CACHE_EX(Symbol, Symbols, SymbolPtr, "Symbol", 512); // use high block size to improve performance because there are lot of symbols
  14. /******************************************************************************/
  15. Str SymbolToPath (C Str &s) {return Replace(Replace(s, '.', SEP), '/', DIV);}
  16. Str PathToSymbol(C Str &s) {return Replace(Replace(s, SEP, '.'), DIV, '/');}
  17. Str SymbolGetBase (C Str &s) {return PathToSymbol(GetBase(SymbolToPath(s)));}
  18. Str SymbolGetPath (C Str &s) {return PathToSymbol(GetPath(SymbolToPath(s)));}
  19. Str NamelessName(Symbol *parent) {return S+"Nameless "+(parent ? S+(parent->nameless_children++) : RandomName());}
  20. /******************************************************************************/
  21. Symbol* GetFinalSymbol(Symbol *symbol, Memc<Symbol::Modif> *templates) // simplified version of Symbol::Modif::proceedToFinal (skips modifiers, const_level, ptr_level, array_dims)
  22. {
  23. for(RecTest rt; symbol; )
  24. {
  25. rt++; if(rt)break;
  26. if(symbol->type==Symbol::TYPENAME)
  27. {
  28. Symbol *temp=symbol;
  29. if(templates)REPA(*templates)
  30. {
  31. Symbol::Modif &templat=(*templates)[i];
  32. if(templat.src_template==symbol)
  33. {
  34. if(templat)symbol=templat();
  35. break;
  36. }
  37. }
  38. if(temp==symbol)break;
  39. }else
  40. if(symbol->isFunc())break;else // we can't proceed to the value of the function without calling it
  41. if(symbol->value)symbol=symbol->value();else
  42. break;
  43. }
  44. return symbol;
  45. }
  46. SymbolPtr FindChild(C Str &name, Symbol *parent, Memc<Symbol::Modif> *parent_templates, Bool allow_base, Bool allow_self, RecTest &rt)
  47. {
  48. IntLock lock(rt); if(rt)return null;
  49. SymbolPtr s; if(allow_self && s.find(parent ? parent->full_name+SEP+name : name))if((s->valid || s->valid_decl) && (CppMode ? !(s->modifiers&Symbol::MODIF_ES_ONLY) : true))return s; // when in CppMode then skip Esenthel Script only keywords
  50. if(allow_base && parent && parent->type==Symbol::CLASS)FREPA(parent->base)
  51. {
  52. Symbol::Modif base=parent->base[i]; base.proceedToFinal(parent_templates);
  53. if(*base==name())return base; // check base itself
  54. if(s=FindChild(name, base(), &base.templates, allow_base, true, rt))return s; // check base members
  55. }
  56. return null;
  57. }
  58. SymbolPtr FindSymbol(C Str &name, Symbol *parent)
  59. {
  60. if(SymbolPtr s=FindChild(name, parent))if(!(s->modifiers&Symbol::MODIF_CTOR_DTOR))return s;
  61. if(parent)return FindSymbol(name, parent->Parent());
  62. return null;
  63. }
  64. SymbolPtr FindSymbol(C Str &name, Symbol *parent, Memc<SymbolPtr> &usings)
  65. {
  66. if(SymbolPtr s=FindSymbol(name, parent))return s;
  67. REPA(usings)if(SymbolPtr s=FindChild(name, usings[i]()))if(!(s->modifiers&Symbol::MODIF_CTOR_DTOR))return s;
  68. return null;
  69. }
  70. /******************************************************************************/
  71. void AddBaseTemplates(Memc<Symbol::Modif> &templates, Symbol &Class, RecTest &rt)
  72. {
  73. IntLock lock(rt); if(rt)return;
  74. REPA(Class.base) // iterate all bases in that class (process in reversed order, so first is most important)
  75. if(Symbol::Modif &base=Class.base[i])
  76. {
  77. AddBaseTemplates(templates, *base, rt); // add bases from that base first, so their templates are listed before the base templates
  78. REPA(base.templates)templates.add(base.templates[i]); // add all templates from that base (process in reversed order, so first is most important)
  79. }
  80. }
  81. /******************************************************************************/
  82. // SYMBOL::MODIF CLASS METHODS
  83. /******************************************************************************/
  84. void Symbol::Modif::clear(Bool clear_templates)
  85. {
  86. const_level=0; ptr_level=0; src_template_i=-1; modifiers=0; array_dims.clear(); src_template.clear();
  87. if(clear_templates)templates.clear();else REPAO(templates).src_template_i=-1;
  88. super::clear();
  89. }
  90. /******************************************************************************/
  91. Bool Symbol::Modif:: isConst( ) {return (const_level&(1<<(ptr_level+array_dims.elms())))!=0;}
  92. void Symbol::Modif::setConst(Bool on) {FlagSet(const_level, 1<<(ptr_level+array_dims.elms()), on);}
  93. /******************************************************************************/
  94. Bool Symbol::Modif:: isObj () {return !ptr_level && !array_dims.elms();}
  95. Bool Symbol::Modif:: isPtr () {return array_dims.elms() ? array_dims.last()==DIM_PTR : ptr_level>0;}
  96. Bool Symbol::Modif:: isArray () {return array_dims.elms() && array_dims.last()!=DIM_PTR;}
  97. Bool Symbol::Modif::anyPtr () {if(ptr_level>0)return true; REPA(array_dims)if(array_dims[i]==DIM_PTR)return true; return false;}
  98. Bool Symbol::Modif::isVoidPtr() {return ptr_level==1 && !array_dims.elms() && T && T->var_type==VAR_VOID;}
  99. Bool Symbol::Modif::basicType() {return (T && T->var_type!=VAR_NONE) || ptr_level>0 || array_dims.elms();}
  100. /******************************************************************************/
  101. Bool Symbol::Modif::same(Modif &modif, Bool test_const, Bool test_ref)
  102. {
  103. if(SCAST(SymbolPtr, T)==SCAST(SymbolPtr, modif)
  104. && ptr_level==modif.ptr_level
  105. && array_dims.elms()==modif.array_dims.elms())
  106. {
  107. REPA(array_dims)if(array_dims[i]!=modif.array_dims[i])return false;
  108. if(test_const && const_level != modif.const_level )return false;
  109. if(test_ref && (modifiers&MODIF_REF)!=(modif.modifiers&MODIF_REF))return false;
  110. for(Symbol *cur=T(); cur; cur=cur->parent()) // check target templates of the symbol and its parents, for example "Memc<Byte> == Memc<Int>" (also parents because they also can have templates "<TYPE> class Main { <TYPE2> class Sub {}}" ) (bases don't need to be searched because they can depend only on the 'cur' temples only, so when checking cur we don't care about the base templates, example: "T1(TYPE) struct B : A<TYPE>")
  111. REPA(cur->templates)if(Symbol *t=cur->templates[i]()) // get 'TYPE' from "Memc<TYPE>"
  112. {
  113. // find that 'TYPE' in:
  114. Modif *a=null; REPA( templates)if( templates[i].src_template==t){a=& templates[i]; break;} // 'T' templates
  115. Modif *b=null; REPA(modif.templates)if(modif.templates[i].src_template==t){b=&modif.templates[i]; break;} // 'modif' templates
  116. if(a || b) // at least one is present
  117. {
  118. if(!a || !b)return false; // at least one is missing
  119. if(!a->same(*b, true, true))return false; // compare both templates, here test const and ref
  120. }
  121. }
  122. return true;
  123. }
  124. return false;
  125. }
  126. Bool Symbol::Modif::sameFuncParamValue(Modif &modif)
  127. {
  128. if(!T() && !modif())return true ; // both are null
  129. if(!T() || !modif())return false; // one is null
  130. if(T()==modif() || (T->type==TYPENAME && modif->type==TYPENAME))
  131. if(const_level==modif.const_level && ptr_level==modif.ptr_level && array_dims.elms()==modif.array_dims.elms() && templates.elms()==modif.templates.elms() && ((modifiers&MODIF_SAME_FUNC_PARAM)==(modif.modifiers&MODIF_SAME_FUNC_PARAM))/* && src_template==modif.src_template*/)
  132. {
  133. REPA(array_dims)if( array_dims[i] != modif.array_dims[i] )return false;
  134. REPA(templates )if(!templates [i]->value.sameFuncParamValue(modif.templates [i]->value))return false; // we need to check templates values (and not templates by themself, because they are only stored as TYPENAME or VAR, value has the actual type or null for TYPENAME, remember that TYPENAME point to different symbols because each template is created in the function location)
  135. return true;
  136. }
  137. return false;
  138. }
  139. Int Symbol::Modif::rawSize(Bool ref_as_ptr_size, RecTest &rt)
  140. {
  141. // check reference at start
  142. if(ref_as_ptr_size && (modifiers&MODIF_REF))return PtrSize; // ignore arrays because "arrays of references are illegal in C++"
  143. // calculate total array dimensions
  144. Int dims=1; REPA(array_dims) // must go from the end to start
  145. {
  146. Int d=array_dims[i];
  147. if( d==DIM_PTR)return dims*PtrSize; // if encountered a pointer {1,2,PTR,4,5} then the size is 4*5*PtrSize
  148. if( d>=1)dims*=d;else
  149. {
  150. // TODO: change to compile error
  151. DEBUG_ASSERT(false, "Unknown array dimensions");
  152. }
  153. }
  154. if(ptr_level)return dims*PtrSize;
  155. if(T )return dims*T->rawSize(ref_as_ptr_size, &templates, rt);
  156. // TODO: compile error
  157. return 0;
  158. }
  159. Int Symbol::Modif::firstMemberSize(RecTest &rt)
  160. {
  161. if(modifiers&MODIF_REF)return PtrSize; // ignore arrays because "arrays of references are illegal in C++"
  162. if(anyPtr() )return PtrSize;
  163. if(T )return T->firstMemberSize(&templates, rt);
  164. return 0;
  165. }
  166. Bool Symbol::Modif::hasConstructor(RecTest &rt)
  167. {
  168. return !(modifiers&MODIF_REF) && !anyPtr() && T && T->hasConstructor(&templates, rt);
  169. }
  170. Bool Symbol::Modif::hasDestructor(RecTest &rt)
  171. {
  172. return !(modifiers&MODIF_REF) && !anyPtr() && T && T->hasDestructor(&templates, rt);
  173. }
  174. Bool Symbol::Modif::constMemAddrOK()
  175. {
  176. REPA(templates)
  177. {
  178. Modif &templat=templates[i];
  179. if(templat.src_template && (templat.src_template->modifiers&MODIF_CONST_MEM_ADDR)) // "<const_mem_addr TYPE> class Memc {..}" if source template has 'const_mem_addr' specified, then it means it will not preserve constant memory address
  180. if(templat && (templat->modifiers&MODIF_CONST_MEM_ADDR)) // if this element requires constant memory address "const_mem_addr class Thread"
  181. if(!(templat.modifiers&MODIF_CONST_MEM_ADDR)) // and not marked to ignore "Memc<const_mem_addr Thread>"
  182. if(!templat.anyPtr()) // "Memc<Thread*>" is ok, so ignore pointers
  183. return false;
  184. if(!templat.constMemAddrOK())return false; // if any sub-templates have issue then fail too, "Memx< Memc<const_mem_addr Thread> >" the Memx is OK but the sub Memc should fail
  185. }
  186. return true;
  187. }
  188. Str Symbol::Modif::modifName(Bool spaces, Bool include_const, Bool include_ref, Bool invalid_array_as_1, Bool template_space)
  189. {
  190. Str s;
  191. if((const_level&1) && include_const)s="const ";
  192. s+=(T ? T->fullCppName() : S+"unknown");
  193. if(T && T->templates.elms()) // Memc<>
  194. {
  195. s+='<';
  196. FREPA(T->templates)
  197. {
  198. if(i){if(spaces)s.space(); s+=',';}
  199. Symbol *src=T->templates[i]();
  200. Modif *target=null;
  201. REPA(templates)if(templates[i].src_template==src){target=&templates[i]; break;}
  202. if(target)s+=target->modifName(spaces);else s+=*src; // here include const and ref
  203. }
  204. if(template_space && s.last()=='>')s+=' ';
  205. s+='>';
  206. }
  207. FREP(ptr_level)
  208. {
  209. if(spaces)s.space(); s+='*';
  210. if(include_const){Int ci=i-1; if(ci>=0 && (const_level&(1<<ci)))s+="const";}
  211. }
  212. REPA(array_dims) // process in reversed order
  213. {
  214. Int d=array_dims[i];
  215. if( d==DIM_PTR)
  216. {
  217. if(spaces)s.space(); s+='*';
  218. if(include_const){Int ci=i-1-ptr_level; if(ci>=0 && (const_level&(1<<ci)))s+="const";}
  219. }else
  220. {
  221. s+='['; if(d>=1)s+=d;else if(invalid_array_as_1)s+='1';
  222. s+=']';
  223. }
  224. }
  225. if((modifiers&MODIF_REF) && include_ref)
  226. {
  227. if(spaces)s.space(); s+='&';
  228. }
  229. return s;
  230. }
  231. void Symbol::Modif::proceedToFinal(Memc<Modif> *templates, Bool func_call, RecTest &rt) // 'templates'=container of all known templates !! this may be T.templates !!
  232. {
  233. IntLock lock(rt); if(rt)return;
  234. for(RecTest lrt; T; )
  235. {
  236. lrt++; if(lrt)break;
  237. if(T->isFunc()){if(func_call)func_call=false;else break;} // we can't proceed to the value of the function without calling it (we can use only one call at a time)
  238. if(T->type==Symbol::TYPENAME)
  239. {
  240. Symbol *temp=T();
  241. if(templates)
  242. REPA(*templates) // go from end (from most recent templates, in case there are many of the same 'src_template')
  243. if((*templates)[i].src_template==T)
  244. {
  245. Modif temp=(*templates)[i]; // we need to store local copy, because 'templates' may belong to this (T.templates), in which case "T.proceedTo(T.templates[i])" may cause errors
  246. proceedTo(temp, rt);
  247. break;
  248. }
  249. if(temp==T())break;
  250. }else
  251. if(T->value)proceedTo(T->value, rt);else
  252. break;
  253. }
  254. if(templates)REPAO(T.templates).proceedToFinal(templates, false, rt);
  255. }
  256. void Symbol::Modif::proceedTo(Modif &src, RecTest &rt) // new order of const,ptr should be : src, T (since 'src' is the more low-level)
  257. {
  258. IntLock lock(rt); if(rt)return;
  259. T =SCAST(SymbolPtr, src);
  260. //src_template=src.src_template; // don't modify 'src_template' because we need to preserve the original so when searching for original we find it but with new target symbol (T, modifiers, ptr_level, ..)
  261. modifiers |=src.modifiers ;
  262. const_level =src.const_level|(T.const_level<<(src.ptr_level+src.array_dims.elms())); // set const keeping 'src.const' as more low-level and 'T.const' as high-level
  263. // set 'ptr_level' and 'array_dims' (order: src.ptr_level, src.array_dims, T.ptr_level, T.array_dims)
  264. if(src.array_dims.elms())
  265. {
  266. Mems<Int> array_dims; // setup new 'array_dims'
  267. array_dims.setNum(src.array_dims.elms() + T.ptr_level + T.array_dims.elms()); // total number of elements = src.array + T.ptr + T.array
  268. FREPA(src.array_dims)array_dims[ i]=src.array_dims[i]; // set src.array
  269. FREP (T .ptr_level )array_dims[src.array_dims.elms()+ i]= DIM_PTR; // set T .ptr
  270. FREPA(T .array_dims)array_dims[src.array_dims.elms()+T.ptr_level+i]=T .array_dims[i]; // set T .array
  271. T.ptr_level=src.ptr_level; // set src.ptr
  272. Swap(T.array_dims, array_dims);
  273. }else
  274. {
  275. ptr_level+=src.ptr_level; // increase 'ptr_level', and keep 'array_dims' as it is
  276. }
  277. // we need to add all templates from 'src' to T
  278. FREPA(src.templates) // order is important
  279. {
  280. Modif templat=src.templates[i]; // first create as temporary variable
  281. templat.proceedToFinal(&templates, false, rt); // 'templat' may be a TYPENAME so use 'proceedToFinal' with all known templates
  282. Swap(templates.New(), templat); // after we have processed it, we can add it to the known templates
  283. }
  284. }
  285. /******************************************************************************/
  286. // SYMBOL CLASS METHODS
  287. /******************************************************************************/
  288. Str Symbol::typeName()
  289. {
  290. switch(type)
  291. {
  292. case KEYWORD : return "Keyword";
  293. case PREPROC : return "Preprocessor Keyword";
  294. case ENUM : return "Enum";
  295. case ENUM_ELM : return "Enum Element";
  296. case TYPEDEF : return "Typedef";
  297. case NAMESPACE: return "Namespace";
  298. case CLASS : return (modifiers&MODIF_UNION) ? "Union" : "Class";
  299. case TYPENAME : return "Typename";
  300. case FUNC_LIST: return "Function List";
  301. case FUNC : return "Function";
  302. case VAR : return "Variable";
  303. case SPACE : return "Local Space";
  304. default : return S;
  305. }
  306. }
  307. Str Symbol::fileName() {if(modifiers&MODIF_NAMELESS)return S+"nameless-"+nameless_index; return Replace(full_name, SEP, SEP_FILE);}
  308. Str Symbol:: cppName() // returns base name only (return NAMELESS names because 'fullCppName' requires it)
  309. {
  310. if(isFunc() )return parent ? PathToSymbol(*parent) : S; // sample FUNC name "Namespace/Func/B123FE", so return parent FUNC_LIST name
  311. if(type==SPACE)return S;
  312. return T;
  313. }
  314. Str Symbol::fullCppName()
  315. {
  316. Str out;
  317. for(Symbol *symbol=this; symbol; symbol=symbol->parent())
  318. if(!symbol->isFunc() && !(symbol->type==CLASS && (symbol->modifiers&MODIF_TRANSPARENT))) // skip FUNC "8761283" and transparent classes (still process nameless classes because of case "class A { class AA {int x;}a,b; int x; };" - there is A.x and A.nameless.x (accessed through A.a.x and A.b.x)
  319. {
  320. Str s=symbol->cppName(); if(s.is()){if(out.is())out=s+'.'+out;else out=s;}
  321. }
  322. return out;
  323. }
  324. Str Symbol::shortName()
  325. {
  326. Str name=cppName(); if(Starts(name, "operator", true, true))name=_SkipStart(name, "operator");
  327. return name;
  328. }
  329. /******************************************************************************/
  330. Str Symbol::definition()
  331. {
  332. if(source && InRange(token_index, source->tokens))
  333. {
  334. if(isVar() || type==FUNC || type==ENUM || type==ENUM_ELM || type==NAMESPACE || type==CLASS || type==TYPEDEF)
  335. {
  336. return source->getText(type_range.x, type_range.y)+' '+source->getText(def_range.x, def_range.y);
  337. }
  338. }
  339. return cppName();
  340. }
  341. Str Symbol::funcDefinition(Int highlight)
  342. {
  343. if(source && InRange(token_index, source->tokens) && type==FUNC)
  344. {
  345. Str s=source->getText(def_range.x, def_range.y);
  346. Int level=0; REPA(s)if(s[i]==')')level--;else if(s[i]=='(')if(!++level){s.clip(i); break;} // remove param list
  347. s=source->getText(type_range.x, type_range.y)+' '+s;
  348. s+='(';
  349. FREPA(params)
  350. {
  351. Symbol &param=*params[i];
  352. if(i)s+=", ";
  353. if(i==highlight)s+="[color=F00]";
  354. s+=source->getText(param.type_range.x, param.def_range.y);
  355. if(i==highlight)s+="[/color]";
  356. }
  357. s+=')';
  358. return s;
  359. }
  360. return cppName();
  361. }
  362. Str Symbol::comments()
  363. {
  364. if(type==KEYWORD) // some keywords are a typedef (like 'ptr')
  365. {
  366. if(T=="continue")return "proceed to the next step of current loop";
  367. if(T=="break" )return "break current loop or case statement";
  368. if(T=="return" )return "return from function";
  369. if(T=="if" )return "Perform conditional code.\n\nSample usage:\n\n int x;\n if(x>0)..; // do codes if x is greater than 0";
  370. if(T=="goto" )return "Jump to specified label (code position).\n\nSample usage:\n\n for(int x=0; x<10; x++)\n {\n for(int y=0; y<10; y++)\n {\n if(..)goto break_both_loops;\n }\n }\nbreak_both_loops: // specify label";
  371. if(T=="sizeof" )return "Obtain size of element in bytes.\n\nSample usage:\n\n byte b;\n sizeof(b ); // 1\n sizeof(byte); // 1\n\n int i;\n sizeof(i ); // 4\n sizeof(int); // 4";
  372. if(T=="this" )return "Get reference to self.\n\nSample usage:\n\n class Class\n {\n int value;\n\n void set(int value) {this.value=value;}\n }";
  373. if(T=="super" || T=="__super")return "Access member/method of a base class.\n\nSample usage:\n\n class BaseClass\n {\n void method() // base method\n {\n }\n }\n class ExtendedClass : BaseClass\n {\n void method() // extended method\n {\n super.method(); // call base method\n }\n }";
  374. if(T=="switch" || T=="case" || T=="default")return "keyword used to perform different codes basing on a value of parameter.\n\nSample usage:\n\nint x;\nswitch(x)\n{\n case 0: .. break; // do codes for 0 value\n\n case 1: .. break; // do codes for 1 value\n\n case 2:\n case 3: .. break; // do codes for 2,3 values\n\n default: .. break; // do codes for all other values\n}";
  375. if(T=="const_mem_addr")return "Element must be stored in constant memory address.\nIf you see this keyword next to a class declaration,\nyou must ensure that when defining objects of that class\nyou will store them in constant memory address,\nthis can be either global namespace or inside 'Memx' 'Meml' containers.";
  376. if(T== "bool" || T=="Bool" )return "Boolean value 'true' or 'false' (8-bit size).";
  377. if(T== "char" || T== "Char" )return "Unicode Character (16-bit size).";
  378. if(T== "cchar" || T=="CChar" )return "Const Unicode Character (16-bit size).";
  379. if(T== "char8" || T== "Char8" )return "Ansi Character (8-bit size).";
  380. if(T== "cchar8" || T=="CChar8" )return "Const Ansi Character (8-bit size).";
  381. if(T== "sbyte" || T=="SByte" || T=="I8" )return "Signed Integer -128 .. 127 (8-bit size).";
  382. if(T== "byte" || T=="Byte" || T=="U8" )return "Unsigned Integer 0 .. 255 (8-bit size).";
  383. if(T== "short" || T=="Short" || T=="I16" )return "Signed Integer -32 768 .. 32 767 (16-bit size).";
  384. if(T== "ushort" || T=="UShort" || T=="U16" )return "Unsigned Integer 0 .. 65 535 (16-bit size).";
  385. if(T== "int" || T=="Int" || T=="I32" )return "Signed Integer -2 147 483 648 .. 2 147 483 647 (32-bit size).";
  386. if(T== "uint" || T=="UInt" || T=="U32" )return "Unsigned Integer 0 .. 4 294 967 295 (32-bit size).";
  387. if(T== "long" || T=="Long" || T=="I64" )return "Signed Integer -9 223 372 036 854 775 808 .. 9 223 372 036 854 775 807 (64-bit size).";
  388. if(T== "ulong" || T=="ULong" || T=="U64" )return "Unsigned Integer 0 .. 18 446 744 073 709 551 615 (64-bit size).";
  389. if(T== "flt" || T=="Flt" || T=="float" )return "Floating Point 1-bit sign + 8-bit exponent + 23-bit fraction (32-bit size).";
  390. if(T== "dbl" || T=="Dbl" || T=="double")return "Floating Point 1-bit sign + 11-bit exponent + 52-bit fraction (64-bit size).";
  391. if(T== "ptr" || T== "Ptr" )return "General Pointer (32-bit or 64-bit).";
  392. if(T== "cptr" || T=="CPtr" )return "General Pointer to const data (32-bit or 64-bit).";
  393. if(T== "intptr" || T== "IntPtr" )return "Signed Integer capable of storing full memory address (32-bit or 64-bit).";
  394. if(T=="uintptr" || T=="UIntPtr" )return "Unsigned Integer capable of storing full memory address (32-bit or 64-bit).";
  395. }
  396. if(source && InRange(token_index, source->tokens) && type!=NAMESPACE && type!=FUNC_LIST)
  397. {
  398. Token &token=*source->tokens[token_index];
  399. if(Line *line=token.line)
  400. {
  401. Str com;
  402. for(Int i=token.col; i<line->length(); i++)if(line->Type(i)==TOKEN_COMMENT)
  403. {
  404. Char c=(*line)[i];
  405. if(!(com.last()==' ' && c==' '))com+=c;
  406. }
  407. if(Starts(com, "//"))com=SkipStart(com, "//");
  408. com=SkipWhiteChars(com);
  409. return com;
  410. }
  411. }
  412. return S;
  413. }
  414. Str Symbol::commentsCode()
  415. {
  416. Str comm=comments(); if(comm.is())comm=S+" [color=080]// "+comm+"[/color]";
  417. return comm;
  418. }
  419. /******************************************************************************/
  420. Symbol* Symbol::Parent()
  421. {
  422. Symbol *p=T.parent(); for(; p && (p->modifiers&MODIF_TRANSPARENT); )p=p->parent();
  423. return p;
  424. }
  425. Symbol* Symbol::rootClass()
  426. {
  427. Symbol *root=null; for(Symbol *symbol=this; symbol; symbol=symbol->parent())if(symbol->type==CLASS)root=symbol;
  428. return root;
  429. }
  430. Symbol* Symbol::Class()
  431. {
  432. for(Symbol *symbol=this; symbol; symbol=symbol->parent())if(symbol->type==CLASS)return symbol;
  433. return null;
  434. }
  435. Symbol* Symbol::Namespace()
  436. {
  437. for(Symbol *symbol=this; symbol; symbol=symbol->parent())if(symbol->type==NAMESPACE)return symbol;
  438. return null;
  439. }
  440. Symbol* Symbol::func()
  441. {
  442. for(Symbol *symbol=this; symbol; symbol=symbol->parent())
  443. {
  444. if(symbol->type==FUNC )return symbol;
  445. if(symbol->type==CLASS || symbol->type==NAMESPACE)return null; // "void func() { class A { int a; void met() {} } }" // let "int a" tokens being child of "class A" don't return 'func'
  446. }
  447. return null;
  448. }
  449. Symbol* Symbol::rootFunc()
  450. {
  451. Symbol *root=null; for(Symbol *symbol=this; symbol; symbol=symbol->parent())if(symbol->type==FUNC)root=symbol;
  452. return root;
  453. }
  454. Symbol* Symbol::firstNonTransparent()
  455. {
  456. for(Symbol *symbol=this; symbol; symbol=symbol->parent())if(!(symbol->modifiers&MODIF_TRANSPARENT))return symbol;
  457. return null;
  458. }
  459. Bool Symbol::contains(Symbol *symbol)
  460. {
  461. for(; symbol; symbol=symbol->parent())if(this==symbol)return true;
  462. return false;
  463. }
  464. /******************************************************************************/
  465. Token* Symbol::getToken() {return source ? source->getToken(token_index) : null;}
  466. /******************************************************************************/
  467. Bool Symbol::insideFunc()
  468. {
  469. for(Symbol *cur=Parent(); cur; cur=cur->Parent())if(cur->type==FUNC || cur->type==FUNC_LIST)return true; // use Parent because when testing FUNC its parent is FUNC_LIST which would result in FUNC being inside func
  470. return false;
  471. }
  472. Bool Symbol::insideClass()
  473. {
  474. if(source)
  475. {
  476. Int start=source->getSymbolStart(token_index); // symbol start must be used for functions "template<typename X> void Class::func(X param)" token.parent of 'func' could have been changed to detect templates
  477. if(InRange(start, source->tokens))return source->tokens[start]->parent==Parent();
  478. }
  479. return false;
  480. }
  481. /******************************************************************************/
  482. Symbol::ACCESS_LEVEL Symbol::highestAccess()
  483. {
  484. if(type==FUNC_LIST)
  485. {
  486. ACCESS_LEVEL level=ACCESS_PRIVATE; REPA(funcs)if(!(funcs[i]->modifiers&MODIF_OUTSIDE_METHOD))MAX(level, ModifToAccessLevel(funcs[i]->modifiers)); // ignore class members defined outside of class because they are not aware of access modifiers "class X{private: void method();} void X::method() {}" - while parsing 2nd method access is unknown
  487. return level;
  488. }
  489. return ModifToAccessLevel(modifiers);
  490. }
  491. Bool Symbol::fullyStatic()
  492. {
  493. if(type==FUNC_LIST)
  494. {
  495. REPA(funcs)if(!(funcs[i]->modifiers&MODIF_STATIC))return false; // if at least one is not static
  496. return true;
  497. }
  498. return FlagTest(modifiers, MODIF_STATIC);
  499. }
  500. Bool Symbol::partiallyStatic()
  501. {
  502. if(type==FUNC_LIST)
  503. {
  504. REPA(funcs)if(funcs[i]->modifiers&MODIF_STATIC)return true; // if at least one is static
  505. return false;
  506. }
  507. return FlagTest(modifiers, MODIF_STATIC);
  508. }
  509. /******************************************************************************/
  510. Bool Symbol::isNativeFunc () {return type==KEYWORD && (T=="sizeof" || T=="typeid" || T=="dynamic_cast" || T=="static_cast" || T=="const_cast" || T=="reinterpret_cast");}
  511. Bool Symbol::isGlobal () {return !Parent() || Parent()->type==NAMESPACE;}
  512. Bool Symbol::isVar () {return type==VAR || (type==FUNC && (func_ptr_level || (modifiers&MODIF_REF)));}
  513. Bool Symbol::isFunc () {return type==FUNC && !(func_ptr_level || (modifiers&MODIF_REF)) ;}
  514. Bool Symbol::isClassNonStaticMember() {return (Parent() && Parent()->type==CLASS) && !(modifiers&MODIF_STATIC);}
  515. Bool Symbol::isClassNonStaticFunc () {return isFunc() && isClassNonStaticMember();}
  516. Bool Symbol::isGlobalFunc () {return isFunc() && isGlobal();}
  517. Bool Symbol::isGlobalAndStatic () {return (modifiers&MODIF_STATIC) && isGlobal();}
  518. Bool Symbol::isGlobalOrStatic () {return (modifiers&MODIF_STATIC) || isGlobal();}
  519. Bool Symbol::isTemplateClass ()
  520. {
  521. for(Symbol *cur=this; cur && cur->type==CLASS; cur=cur->parent())if(cur->templates.elms())return true; // if any of class parents has templates
  522. return false;
  523. }
  524. Bool Symbol::insideTemplateClass()
  525. {
  526. if(Symbol *parent=Parent())return parent->isTemplateClass();
  527. return false;
  528. }
  529. Bool Symbol::isTemplateFunc()
  530. {
  531. if(isFunc())
  532. {
  533. if(templates.elms() // func is "template func" if it has templates
  534. || insideTemplateClass())return true; // or any of its class parents has templates
  535. }
  536. return false;
  537. }
  538. Bool Symbol::isInlineFunc()
  539. {
  540. if(isFunc())
  541. {
  542. if(modifiers&MODIF_INLINE // inline, below check for templates, because template functions are also inline
  543. || templates.elms() // func is "template func" if it has templates
  544. || insideTemplateClass())return true; // or any of its class parents has templates
  545. }
  546. return false;
  547. }
  548. Bool Symbol::isAbstractClass(Memc<Modif> *templates, RecTest &rt)
  549. {
  550. // TODO: this doesn't check class bases
  551. IntLock lock(rt); if(rt)return false;
  552. REPA(children)if(Symbol *func_list=children[i])if(func_list->type==FUNC_LIST)
  553. {
  554. REPA(func_list->funcs)if((func_list->funcs[i]->modifiers&MODIF_VIRTUAL) && (func_list->funcs[i]->modifiers&MODIF_DEF_VALUE))return true; // check all functions for 'virtual' and "=NULL"
  555. }
  556. return false;
  557. }
  558. Bool Symbol::hasVirtualDestructor(Memc<Modif> *templates, RecTest &rt) // assumes 'T.children' is set
  559. {
  560. IntLock lock(rt); if(rt)return false;
  561. REPA(children)if(Symbol *func_list=children[i])if(func_list->modifiers&MODIF_DTOR) // if we've encountered destructor
  562. {
  563. REPA(func_list->funcs)if(func_list->funcs[i]->modifiers&MODIF_VIRTUAL)return true; // check all functions
  564. break; // don't check other function lists
  565. }
  566. REPA(base)
  567. {
  568. Modif base=T.base[i]; base.proceedToFinal(templates); if(base->hasVirtualDestructor(&base.templates, rt))return true;
  569. }
  570. return false;
  571. }
  572. Bool Symbol::hasVirtualFunc(Symbol &func, Memc<Modif> *templates, RecTest &rt) // assumes 'T.children' is set
  573. {
  574. IntLock lock(rt); if(rt)return false;
  575. C Str &func_name=((func.parent && func.parent->type==FUNC_LIST) ? *func.parent : func); // get the name from the function list if possible
  576. REPA(children)if(Symbol *func_list=children[i])if(func_list->type==FUNC_LIST && *func_list==func_name()) // found function list with identical name
  577. {
  578. REPA(func_list->funcs)if(Symbol *f=func_list->funcs[i]())if((f->modifiers&MODIF_VIRTUAL) && func.sameFunc(*f))return true; // continue checking other functions because there can be multiple same (with body, or without, or multiple declarations)
  579. break;
  580. }
  581. REPA(base)
  582. {
  583. Modif base=T.base[i]; base.proceedToFinal(templates); if(base->hasVirtualFunc(func, &base.templates, rt))return true;
  584. }
  585. return false;
  586. }
  587. Bool Symbol::isVirtualClass(Memc<Modif> *templates, RecTest &rt) // assumes 'T.children' is set
  588. {
  589. IntLock lock(rt); if(rt)return false;
  590. REPA(children)if(Symbol *func_list=children[i])if(func_list->type==FUNC_LIST) // if we've encountered function list
  591. {
  592. REPA(func_list->funcs)if(func_list->funcs[i]->modifiers&MODIF_VIRTUAL)return true; // check all functions
  593. }
  594. REPA(base)
  595. {
  596. Modif base=T.base[i]; base.proceedToFinal(templates); if(base->isVirtualClass(&base.templates, rt))return true;
  597. }
  598. return false;
  599. }
  600. Bool Symbol::isVirtualFunc(Memc<Modif> *templates) // assumes 'T.children' is set
  601. {
  602. if(modifiers&MODIF_VIRTUAL)return true;
  603. if(modifiers&MODIF_DTOR ) // destructor needs to be checked separately (there are no virtual constructors, so skip them)
  604. {
  605. if(Symbol *Class=T.Class())return Class->hasVirtualDestructor(templates);
  606. }else
  607. if(isClassNonStaticFunc()) // if at least one identical function in base classes is virtual then this is virtual too
  608. {
  609. if(Symbol *Class=T.Class())return Class->hasVirtualFunc(T, templates);
  610. }
  611. return false;
  612. }
  613. Bool Symbol::hasConstructor(Memc<Modif> *templates, RecTest &rt) // assumes 'T.children' is set
  614. {
  615. IntLock lock(rt); if(rt)return false;
  616. REPA(children)
  617. if(Symbol *child=children[i])
  618. if(!(child->modifiers&MODIF_STATIC)) // non-static child
  619. {
  620. if(child->modifiers&MODIF_CTOR)return true; // we have found constructor
  621. if(child->isVar() && (child->modifiers&MODIF_DEF_VALUE))return true; // if is a variable (include function pointers) and has default value specified
  622. REPA(child->funcs)if(child->funcs[i]->modifiers&MODIF_VIRTUAL)return true; // if at least one function is virtual, then this class needs constructor
  623. if( child->type==VAR // check variables (skip function pointers)
  624. || (child->type==CLASS && (child->modifiers&MODIF_TRANSPARENT))) // transparent class
  625. {
  626. Modif value=child->value; value.proceedToFinal(templates); if(value.hasConstructor(rt))return true; // if any type of variable has constructor, then this class needs constructor
  627. }
  628. }
  629. REPA(base)
  630. {
  631. Modif base=T.base[i]; base.proceedToFinal(templates); if(base.hasConstructor(rt))return true;
  632. }
  633. return false;
  634. }
  635. Bool Symbol::hasDestructor(Memc<Modif> *templates, RecTest &rt) // assumes 'T.children' is set
  636. {
  637. IntLock lock(rt); if(rt)return false;
  638. REPA(children)
  639. if(Symbol *child=children[i])
  640. if(!(child->modifiers&MODIF_STATIC)) // non-static child
  641. {
  642. if(child->modifiers&MODIF_DTOR)return true; // we have found destructor
  643. REPA(child->funcs)if(child->funcs[i]->modifiers&MODIF_VIRTUAL)return true; // if at least one function is virtual, then this class needs destructor
  644. if( child->type==VAR // check variables (skip function pointers)
  645. || (child->type==CLASS && (child->modifiers&MODIF_TRANSPARENT))) // transparent class
  646. {
  647. Modif value=child->value; value.proceedToFinal(templates); if(value.hasDestructor(rt))return true; // if any type of variable has destructor, then this class needs destructor
  648. }
  649. }
  650. REPA(base)
  651. {
  652. Modif base=T.base[i]; base.proceedToFinal(templates); if(base.hasDestructor(rt))return true;
  653. }
  654. return false;
  655. }
  656. Bool Symbol::hasResult(Memc<Modif> *templates, Modif *result_value)
  657. {
  658. if(type==FUNC && !(modifiers&(MODIF_CTOR|MODIF_DTOR))) // constructors don't use return, destructors are always void
  659. {
  660. Modif value=T.value; value.proceedToFinal(templates);
  661. DEBUG_ASSERT(value && value->type!=TYPENAME, "Symbol::hasResult");
  662. if(!(value.isObj() && value && value->var_type==VAR_VOID)) // false for "void", true for everything else (including "void*")
  663. {
  664. if(result_value)Swap(*result_value, value);
  665. return true;
  666. }
  667. }
  668. return false;
  669. }
  670. Bool Symbol::fullyPublic()
  671. {
  672. for(Symbol *cur=this; cur; cur=cur->Parent())if(ModifToAccessLevel(cur->modifiers)!=ACCESS_PUBLIC)return false;
  673. return true;
  674. }
  675. Int Symbol::templateClasses()
  676. {
  677. Int tc=0; for(Symbol *cur=Parent(); cur && cur->type==CLASS; cur=cur->Parent())if(cur->templates.elms())tc++; // if class has templates, can use Parent to skip transparent classes because those can't have templates, use Parent also to skip FUNC_LIST
  678. return tc;
  679. }
  680. Int Symbol::baseOffset(Int base_index, Memc<Modif> *templates, RecTest &rt)
  681. {
  682. Int offset=0;
  683. // check virtual func table offset
  684. Bool base0_virtual=false; if(base.elms()){Modif base0=base[0]; base0.proceedToFinal(templates); if(base0 && base0->isVirtualClass(&base0.templates))base0_virtual=true;}
  685. if( !base0_virtual && isVirtualClass(templates))offset=PtrSize; // if this is virtual and 1st base is not, then we need to add virtual
  686. MIN( base_index, base.elms());
  687. FREP(base_index) // iterate the first bases
  688. {
  689. Symbol::Modif b=base[i]; b.proceedToFinal(templates);
  690. Int base_size=b.rawSize(true, rt),
  691. base_pos =AlignAddress(offset, Min(class_pack, b.firstMemberSize(rt)));
  692. offset=base_pos+base_size;
  693. }
  694. return offset;
  695. }
  696. Int Symbol::memberOffset(Symbol *member, Bool *found, Memc<Modif> *templates, RecTest &rt)
  697. {
  698. if(found)*found=false;
  699. Int pos=baseOffset(base.elms(), templates, rt), total_size=pos;
  700. // iterate members
  701. FREPA(children)
  702. if(Symbol *child=children[i])
  703. if((child->isVar() && !(child->modifiers&MODIF_STATIC )) // non-static variables
  704. || (child->type==CLASS && (child->modifiers&MODIF_TRANSPARENT))) // transparent classes
  705. {
  706. Int child_size=child->rawSize(true, templates, rt),
  707. child_pos =AlignAddress(pos, Min(class_pack, child->firstMemberSize(templates, rt)));
  708. if( child==member){if(found)*found=true; return child_pos;}
  709. if(modifiers&MODIF_UNION)MAX(total_size, child_pos+child_size); // if this 'class' is an 'union' then use max size of all members
  710. else pos=total_size= child_pos+child_size;
  711. }
  712. // make sure that first element is aligned at the end as well : "class A{int a; byte b;}" -> SIZE(A)==8 (4 for 'a', 1 for 'b', 3 padd so that next 'a' is aligned)
  713. return AlignAddress(total_size, Min(class_pack, firstMemberSize(templates, rt)));
  714. }
  715. Int Symbol::rawSize(Bool ref_as_ptr_size, Memc<Modif> *templates, RecTest &rt)
  716. {
  717. IntLock lock(rt); if(rt)return 0;
  718. switch(type)
  719. {
  720. case FUNC: if(isVar())return PtrSize; break; // pointer to function
  721. case VAR: {Modif modif=value; modif.proceedToFinal(templates); return modif.rawSize(ref_as_ptr_size, rt);}
  722. case TYPEDEF: // check typedefs and keywords in the same group (because some keywords may be typedefs and vice-versa)
  723. case KEYWORD:
  724. if(value){Modif modif=value; modif.proceedToFinal(templates); return modif.rawSize(ref_as_ptr_size, rt);} // first check if it's a typedef
  725. return TypeSize(var_type);
  726. break;
  727. case ENUM: return EnumSize;
  728. case CLASS: return memberOffset(null, null, templates, rt);
  729. }
  730. return 0;
  731. }
  732. Int Symbol::firstMemberSize(Memc<Modif> *templates, RecTest &rt)
  733. {
  734. IntLock lock(rt); if(rt)return 0;
  735. switch(type)
  736. {
  737. case FUNC: if(isVar())return PtrSize; break; // pointer to function
  738. case VAR: {Modif modif=value; modif.proceedToFinal(templates); return modif.firstMemberSize(rt);}
  739. case TYPEDEF: // check typedefs and keywords in the same group (because some keywords may be typedefs and vice-versa)
  740. case KEYWORD:
  741. if(value){Modif modif=value; modif.proceedToFinal(templates); return modif.firstMemberSize(rt);} // first check if it's a typedef
  742. return TypeSize(var_type);
  743. break;
  744. case ENUM: return EnumSize;
  745. case CLASS:
  746. {
  747. if(isVirtualClass(templates, rt))return Min(class_pack, PtrSize);
  748. FREPA(base){Symbol::Modif b=base[i]; b.proceedToFinal(templates); if(Int size=b.firstMemberSize(rt))return Min(class_pack, size);}
  749. Int max_size=0;
  750. FREPA(children)
  751. if(Symbol *child=children[i])
  752. if((child->isVar() && !(child->modifiers&MODIF_STATIC )) // non-static variables
  753. || (child->type==CLASS && (child->modifiers&MODIF_TRANSPARENT))) // transparent classes
  754. if(Int size=child->firstMemberSize(templates, rt))
  755. if(modifiers&MODIF_UNION)MAX(max_size, size); // from union we must pick the biggest element
  756. else return Min(class_pack, size);
  757. return Min(class_pack, max_size);
  758. }break;
  759. }
  760. return 0;
  761. }
  762. Int Symbol::realParams()
  763. {
  764. if(parent) // func FUNC has "29386481" name, so check the FUNC_LIST parent
  765. if(*parent=="operator++"
  766. || *parent=="operator--")
  767. return 0; // ignore dummy "(int)" param
  768. return params.elms();
  769. }
  770. /******************************************************************************/
  771. Bool Symbol::sameFunc(Symbol &f)
  772. {
  773. if(value.sameFuncParamValue(f.value))
  774. {
  775. if((modifiers&MODIF_SAME_FUNC)!=(f.modifiers&MODIF_SAME_FUNC))return false;
  776. if(params.elms()!=f.params.elms())return false;
  777. REPA(params)if(!(params[i]->value.sameFuncParamValue(f.params[i]->value)))return false;
  778. return true;
  779. }
  780. return false;
  781. }
  782. Bool Symbol::sameSymbol(Symbol &s)
  783. {
  784. return this==&s // if exactly the same
  785. || (parent==s.parent && type==Symbol::FUNC && s.type==Symbol::FUNC && sameFunc(s)); // or 2 FUNC that share the same parent (FUNC_LIST) and are the same
  786. }
  787. /******************************************************************************/
  788. Bool Symbol::constDefineInHeader() // if define const in header
  789. {
  790. Symbol::Modif value; value=this; value.proceedToFinal(null);
  791. if(value)return value.const_level==1 && !value.anyPtr() && IntType(value->var_type); // !anyPtr: accept OBJ (int x=5) and ARRAY (int x[]={1, 2})
  792. return false;
  793. }
  794. Bool Symbol::fromPartialMacro()
  795. {
  796. if(Token *token=getToken()) // found token
  797. if(token->macro_col>=0) // token was created by a macro
  798. {
  799. if(Token *prev=source->getToken(source->getSymbolStart(token_index)-1)) // if there's a token before the declaration of this symbol
  800. if(prev->sameMacro(*token))return true; // if that token was created by the same macro
  801. if(Token *next=source->getToken(source->getListEnd (token_index)+1)) // if there's a token after the declaration of this symbol
  802. if(next->sameMacro(*token))return true; // if that token was created by the same macro
  803. }
  804. return false;
  805. }
  806. /******************************************************************************/
  807. Bool Symbol::hasBase(Symbol *Class, Memc<Modif> *templates, RecTest &rt)
  808. {
  809. if(this==Class)return true;
  810. IntLock lock(rt); if(rt)return false;
  811. REPA(base)
  812. {
  813. Modif base=T.base[i]; base.proceedToFinal(templates); if(base->hasBase(Class, &base.templates, rt))return true;
  814. }
  815. return false;
  816. }
  817. Bool Symbol::hasNonPrivateBase(Symbol *Class, Memc<Modif> *templates, Bool allow_self, Bool test_private, RecTest &rt)
  818. {
  819. if(allow_self && this==Class)return true;
  820. IntLock lock(rt); if(rt)return false;
  821. REPA(base)
  822. {
  823. Modif &b=base[i];
  824. if(test_private ? !FlagTest(b.modifiers, MODIF_PRIVATE) : true)
  825. {
  826. Modif base=b; base.proceedToFinal(templates); if(base->hasNonPrivateBase(Class, &base.templates, true, true, rt))return true;
  827. }
  828. }
  829. return false;
  830. }
  831. Bool Symbol::hasPrivateBase(Symbol *Class, Memc<Modif> *templates, Bool test_private, RecTest &rt)
  832. {
  833. IntLock lock(rt); if(rt)return false;
  834. REPA(base)
  835. {
  836. Modif base=T.base[i]; base.proceedToFinal(templates);
  837. if(test_private ? FlagTest(base.modifiers, MODIF_PRIVATE) : false)
  838. {
  839. if(base->hasBase(Class, &base.templates, rt))return true;
  840. }else
  841. {
  842. if(base->hasPrivateBase(Class, &base.templates, true, rt))return true;
  843. }
  844. }
  845. return false;
  846. }
  847. Bool Symbol::hasNonPublicBase(Symbol *Class , Memc<Modif> *templates, Bool test_access, RecTest &rt)
  848. {
  849. IntLock lock(rt); if(rt)return false;
  850. REPA(base)
  851. {
  852. Modif base=T.base[i]; base.proceedToFinal(templates);
  853. if(test_access ? FlagTest(base.modifiers, MODIF_PRIVATE|MODIF_PROTECTED) : false)
  854. {
  855. if(base->hasBase(Class, &base.templates, rt))return true;
  856. }else
  857. {
  858. if(base->hasNonPublicBase(Class, &base.templates, true, rt))return true;
  859. }
  860. }
  861. return false;
  862. }
  863. Bool Symbol::isMemberOf(Symbol *symbol, Memc<Symbol::Modif> &symbol_templates, Symbol *caller, Bool instance, Bool ctor_init, Bool allow_self, Bool allow_bases) // this checks only direct members of 'symbol' and if they can be called from 'caller' space (ignores parents of 'symbol', but includes bases of 'symbol'), 'instance'=if 'symbol' is an instance, 'ctor_init'=if this is a ctor init ("class A{ A():HERE(){}}")
  864. {
  865. if(type==KEYWORD || type==PREPROC || type==TYPENAME)return false;
  866. Bool caller_is_namespace=(!caller || caller->type==NAMESPACE);
  867. Symbol *caller_class =(caller ? caller->Class() : null),
  868. *Parent =T.Parent(); // skip FUNC_LIST and transparent classes
  869. ACCESS_LEVEL access =highestAccess();
  870. if((modifiers&MODIF_CTOR_DTOR) && !caller_is_namespace)return false; // constructors can be listed only in namespaces
  871. symbol=GetFinalSymbol(symbol);
  872. // if we're specifying something with class/namespace address then it's possible to use instance and non-instance symbols (if the class is caller or base of it), example "class X { int x; void met() {X.|} }"
  873. Bool ignore_instance=false;
  874. if(!instance)
  875. if(caller_class)
  876. if(Symbol *caller_func=caller->func()) // allow access only from functions
  877. if(caller_func->isClassNonStaticFunc()) // allow access only from non-static functions
  878. if(caller_class->hasNonPrivateBase(symbol))
  879. ignore_instance=true;
  880. if(!ignore_instance)
  881. {
  882. if(instance)
  883. {
  884. if((type==CLASS && !allow_bases) || type==NAMESPACE || type==ENUM || type==ENUM_ELM || type==TYPEDEF/* || fullyStatic()*/)return false; // don't check for 'fullyStatic' because for example "EE.D.clear()" where 'clear' is static method but can be accessed
  885. if(access==ACCESS_PROTECTED && !caller_is_namespace)if(!symbol || !symbol->hasNonPrivateBase(caller_class, &symbol_templates))return false; // formula obtained using hand-made tests (works!)
  886. }else
  887. if(type==VAR || type==FUNC || type==FUNC_LIST) // if it's a member
  888. if(Parent && Parent->type==CLASS)
  889. {
  890. Bool allow_func=(symbol && symbol->type==Symbol::CLASS && caller_is_namespace); // if we're defining function body outside of class space (in some namespace) then allow listing functions as members "void Class::method"
  891. if(!( type==FUNC_LIST && allow_func)
  892. && !((type==VAR || type==FUNC) && ctor_init ))
  893. if(!partiallyStatic())return false; // can't access non-static members from non-instance
  894. }
  895. }
  896. if(!Parent && !symbol )return true; // if both are global namespace
  897. if(ctor_init )return symbol==Parent; // constructor initializers can be used only from the same class
  898. if(access==ACCESS_PRIVATE && !caller_is_namespace)if(Parent!=caller_class )return false; // private members can be used only from the same class
  899. if(access==ACCESS_PROTECTED && !caller_is_namespace)if(!caller_class || !caller_class->hasNonPrivateBase(Parent))return false; // protected members can be used only from extended classes
  900. if(caller_class && caller_class->hasPrivateBase(Parent))return false; // we're trying to access from extended class -> base class "class Base{int x;} class Middle : private Base{} class Ext : Middle{|}"
  901. if(symbol && symbol->hasNonPublicBase(Parent, &symbol_templates, true))if(!caller_class || !caller_class->hasBase(symbol))return false; // we're trying to access from base class -> extended class -> base class) "class Base{void method(){Middle m; m.|}} class Middle : private Base{}
  902. Symbol *base=Parent; if(allow_bases && type==CLASS)base=this;
  903. return symbol ? symbol->hasNonPrivateBase(base, &symbol_templates, allow_self) : false;
  904. }
  905. Bool Symbol::canBeAccessedFrom(Symbol *path, Symbol *caller, Bool precise_parent, Memc<SymbolPtr> &usings) // check if all symbols from 'path' and above (parents and bases are checked, however without children) can be accessed from 'caller' space
  906. {
  907. if(type==KEYWORD && precise_parent)return false;
  908. if(modifiers&MODIF_CTOR_DTOR )return false;
  909. Symbol *Parent=T.Parent(); // skip FUNC_LIST and transparent classes
  910. if(type==VAR || type==FUNC || type==FUNC_LIST)
  911. {
  912. Symbol *caller_class=(caller ? caller->Class() : null);
  913. if(highestAccess()==ACCESS_PRIVATE)if(Parent!=caller_class)return false; // private members can be used only from the same class
  914. if(Parent && Parent->type==CLASS && !partiallyStatic()) // if 'this' is a non-static member/method of a class
  915. {
  916. Bool accessible=false;
  917. if(caller_class)
  918. if(Symbol *caller_func=caller->func()) // allow access only from functions
  919. if(caller_func->isClassNonStaticFunc()) // allow access only from non-static functions
  920. accessible=caller_class->hasNonPrivateBase(Parent);
  921. if(!accessible)return false;
  922. }
  923. }
  924. // check used namespaces
  925. REPA(usings)if(usings[i]==Parent)return true;
  926. // first parent of this must be included in 'path' or its parents list (this includes the case when parent==null) or their base list
  927. for(;;)
  928. {
  929. if(Parent==path)return true;
  930. if( !path)return false;
  931. if(path->hasBase(Parent))return true;
  932. path=path->parent();
  933. }
  934. }
  935. /******************************************************************************/
  936. void Symbol::adjustIndex(Memc<Token> &tokens, Int &i)
  937. {
  938. if(InRange(i, tokens))i=tokens[i].source_index;
  939. }
  940. void Symbol::adjustIndexes(Memc<Token> &tokens)
  941. {
  942. if(!(helper&HELPER_ADJUSTED_INDEXES)) // needed in case there are many symbol defs pointing to the same symbol
  943. {
  944. helper|=HELPER_ADJUSTED_INDEXES;
  945. adjustIndex(tokens, token_index );
  946. adjustIndex(tokens, type_range.x);
  947. adjustIndex(tokens, type_range.y);
  948. adjustIndex(tokens, def_range.x);
  949. adjustIndex(tokens, def_range.y);
  950. adjustIndex(tokens, def_val_range.x);
  951. adjustIndex(tokens, def_val_range.y);
  952. }
  953. }
  954. /******************************************************************************/
  955. void Symbol::addDependency(Modif &symbol)
  956. {
  957. Modif final=symbol;
  958. for(Int i=0; final && i<64; i++) // find first value which has 'rootClass'
  959. {
  960. if(Symbol *root=final->rootClass()) // we need to be actually dependent on the root class of symbol (because only root classes are stored as headers)
  961. {
  962. if(final->valid && !(final.modifiers&MODIF_REF) && !final.anyPtr()) // ignore references and pointers
  963. {
  964. if(final->type==TYPENAME)dependencies.include(final()); // if this is a TYPENAME, then add dependency to it and only to class using it "<TYPE> class A { TYPE t; }" A depends on TYPE, "<TYPE> class A { class Sub {TYPE t;} }" Sub depends on TYPE
  965. if(root!=this && !(root->helper&HELPER_PROCESSED))dependencies.include(root); // ignore self-dependencies
  966. }
  967. break;
  968. }
  969. final.proceedTo(final->value); // proceed to next value
  970. }
  971. }
  972. void Symbol::addDependencyIfNested(Symbol *symbol) // if 'symbol' is nested (defined inside some class) then add dependency to that "root class" to this (this ignores references and pointers because we are interested in only declaration of the symbol - its existence)
  973. {
  974. if(symbol && symbol->type!=TYPENAME) // ignore unresolved templates
  975. if(Symbol *root=symbol->rootClass()) // get the root of symbol
  976. if(root!=symbol // if 'symbol' is nested
  977. && root!=this) // if 'root' is not this
  978. if(!(root->helper&HELPER_PROCESSED))dependencies.include(root);
  979. }
  980. /******************************************************************************/
  981. void Symbol::clearBody()
  982. {
  983. if(isFunc() && (modifiers&MODIF_FUNC_BODY))
  984. {
  985. FlagDisable(helper, HELPER_FUNC_PARSED);
  986. nameless_children=0;
  987. ctor_inits.clear();
  988. if(source)for(Int i=source->getBodyStart(token_index), level=0; InRange(i, source->tokens); i++)
  989. {
  990. Token &token=*source->tokens[i];
  991. token.parent=this;
  992. if(token=='{') ++level;else
  993. if(token=='}')if(--level<=0)break;
  994. }
  995. }
  996. }
  997. /******************************************************************************/
  998. }}
  999. /******************************************************************************/