1 #include "CppBase.h"
2 #include "Internal.h"
3
4 namespace Upp {
5
6 #define LLOG(x) // DLOG(x)
7 #define LTIMING(x) // DTIMING(x)
8
ThrowError(const String & e)9 void Parser::ThrowError(const String& e)
10 {
11 err(GetLine(lex.Pos()), e);
12 #ifdef _DEBUG
13 int i = 0;
14 while(i < 40 && lex[i] != t_eof)
15 i++;
16 LLOG("ERROR: (" << GetLine(lex.Pos()) << ") " << e << ", scope: " << current_scope <<
17 ", code: " << AsCString(String(lex.Pos(), lex.Pos(i))));
18 #endif
19 throw Error();
20 }
21
bew(const char * s,const char * t)22 inline const char *bew(const char *s, const char *t)
23 {
24 while(*s)
25 if(*s++ != *t++)
26 return NULL;
27 return t;
28 }
29
30 // String == String comparison is likely faster than String == const char * comparison
31 static String s_operator("operator");
32 static String s_virtual("virtual");
33 static String s_inline("inline");
34 static String s_static("static");
35
sSpaces(String & res,const char * & s)36 static inline bool sSpaces(String& res, const char *& s)
37 {
38 if((byte)*s <= ' ') {
39 char c = *s++;
40 if(c != '\2' && c != '\x1f') {
41 res.Cat(' ');
42 while((byte)*s <= ' ' && *s)
43 s++;
44 }
45 return true;
46 }
47 return false;
48 }
49
FnItem(const char * s,const char * pname,const char * qname,const String & name,bool oper)50 String FnItem(const char *s, const char *pname, const char *qname, const String& name, bool oper)
51 { // Converts function natural text to (unqualified) item
52 String res;
53 while(*s && (byte)*s <= ' ') s++;
54 while(*s) { // Get the name of function into res
55 while(*s && !iscid(*s) && *s != '~')
56 if(*s == '[') { // Skip MSVC attributes
57 while(*s)
58 if(*s++ == '[')
59 break;
60 }
61 else
62 s++;
63 int lvl = 0;
64 int plvl = 0;
65 for(;;) {
66 if(*s == '<' && plvl == 0 && !oper) { // resolve template params, like Fn<int, true>
67 res.Cat(*s++);
68 lvl++;
69 }
70 if(*s == '>' && plvl == 0 && !oper) {
71 res.Cat(*s++);
72 lvl--;
73 }
74 if(*s == '(' && lvl) {
75 res.Cat(*s++);
76 plvl++;
77 }
78 if(*s == ')') {
79 res.Cat(*s++);
80 plvl--;
81 }
82 if(iscid(*s) || *s == '~' || *s && lvl)
83 res.Cat(*s++);
84 else
85 break;
86 }
87 if(res == s_operator) {
88 while(*s && *s != '(') {
89 if((byte)*s >= ' ')
90 res.Cat(*s);
91 s++;
92 }
93 break;
94 }
95 while(*s && (byte)*s <= ' ')
96 s++;
97 if(*s == '(' && (res == name || res == '~' + name))
98 break;
99 res.Clear();
100 }
101 bool wasid = false;
102 while(*s) {
103 const char *w = bew(qname, s);
104 byte c = *s;
105 if(w && w > s && !iscid(*w)) {
106 if(iscid(*res.Last()))
107 res.Cat(' ');
108 res.Cat(name);
109 s = w;
110 wasid = true;
111 }
112 else
113 if(iscid(c)) {
114 const char *b = s++;
115 while(iscid(*s)) s++;
116 String q(b, s);
117 if(q != s_virtual && q != s_inline && q != s_static && !InScList(q, pname)) {
118 if(iscid(*res.Last()))
119 res.Cat(' ');
120 res.Cat(q);
121 }
122 else
123 while((byte)*s <= ' ' && *s) s++;
124 wasid = true;
125 }
126 else
127 if(c == '=') {
128 s++;
129 int l = 0;
130 int tl = 0;
131 while(*s && !(l == 0 && (*s == ',' && tl == 0 || *s == ')'))) {
132 if(*s == '(' || *s == '[')
133 l++;
134 else
135 if(*s == ')' || *s == ']')
136 l--;
137 if(*s == '<') // we always consider < > to be template bracket, not operator here
138 tl++;
139 else
140 if(*s == '>')
141 tl--;
142 s++;
143 }
144 }
145 else
146 if((byte)*s <= ' ') {
147 s++;
148 while((byte)*s <= ' ' && *s)
149 s++;
150 }
151 else
152 if(c == '[' && !wasid) { // Skip MSVC attribute
153 while(*s)
154 if(*s++ == ']')
155 break;
156 }
157 else
158 if(c == '-' && s[1] == '>')
159 break; // trailing return type
160 else {
161 res.Cat(c);
162 if(c == ',')
163 wasid = false;
164 s++;
165 }
166 }
167 return res;
168 }
169
Purify(const char * s,const char * qname,const String & name)170 String Purify(const char *s, const char *qname, const String& name) {
171 String res;
172 while(*s && (byte)*s <= ' ') s++;
173 bool wasid = false;
174 bool firstpar = true;
175 while(*s) {
176 const char *w = bew(qname, s);
177 if(w && w > s) {
178 res.Cat(name);
179 s = w;
180 wasid = true;
181 }
182 else
183 if(iscid(*s)) {
184 const char *b = s++;
185 while(iscid(*s)) s++;
186 String q(b, s);
187 if(q != s_virtual && q != s_inline && q != s_static)
188 res.Cat(q);
189 else
190 while((byte)*s <= ' ' && *s) s++;
191 wasid = true;
192 }
193 else
194 if(*s == '[' && !wasid) { // skip MSVC attribute
195 do {
196 while(*s)
197 if(*s++ == ']')
198 break;
199 while(*s == ' ' || *s == '\2' || *s == '\x1f')
200 s++;
201 }
202 while(*s == '[');
203 }
204 else
205 if(!sSpaces(res, s)) {
206 if(*s == ',')
207 wasid = false;
208 if(*s == '(' && firstpar)
209 wasid = firstpar = false;
210 res.Cat(*s++);
211 }
212 }
213 return TrimRight(res);
214 }
215
Purify(const char * s)216 String Purify(const char *s) {
217 String res;
218 while(*s && (byte)*s <= ' ') s++;
219 while(*s) {
220 if(iscid(*s)) {
221 const char *b = s++;
222 while(iscid(*s)) s++;
223 String q(b, s);
224 if(q != s_virtual && q != s_inline)
225 res.Cat(q);
226 else
227 while((byte)*s <= ' ' && *s) s++;
228 }
229 else
230 if(!sSpaces(res, s))
231 res.Cat(*s++);
232 }
233 return TrimRight(res);
234 }
235
Gpurify(const char * s)236 String Gpurify(const char *s)
237 {
238 String res;
239 while(*s)
240 if(!sSpaces(res, s))
241 res.Cat(*s++);
242 return res;
243 }
244
ScAdd(String & s,const String & a)245 void ScAdd(String& s, const String& a)
246 {
247 if(a.IsEmpty()) return;
248 if(!s.IsEmpty())
249 s << ';';
250 s << a;
251 }
252
253
TpSkip(CParser & p)254 void TpSkip(CParser& p)
255 {
256 int lvl = 0;
257 for(;;) {
258 if(lvl == 0 && (p.IsChar(',') || p.IsChar('>')) || p.IsEof())
259 break;
260 if(p.Char('<'))
261 lvl++;
262 else
263 if(p.Char('>'))
264 lvl--;
265 else
266 p.SkipTerm();
267 }
268 }
269
Subst(const String & s,const Vector<String> & tpar)270 String Subst(const String& s, const Vector<String>& tpar)
271 {
272 if(tpar.GetCount() == 0)
273 return s;
274 String r;
275 CParser p(s);
276 while(!p.IsEof()) {
277 if(p.IsId()) {
278 String id = p.ReadId();
279 int q = FindIndex(tpar, id);
280 if(q >= 0)
281 r << AsString(q);
282 else
283 r << id;
284 }
285 else
286 r << p.GetChar();
287 }
288 return r;
289 }
290
CleanTp(const String & tp)291 String CleanTp(const String& tp)
292 {
293 int q = tp.Find('<');
294 int w = tp.ReverseFind('>');
295 if(q < 0 || w < 0) return tp;
296 String a = TrimLeft(TrimRight(tp.Mid(q + 1, w - q - 1)));
297 const char *s = a;
298 String r;
299 while(*s) {
300 if(*s == ',') {
301 r.Cat(';');
302 s++;
303 while(*s && *s <= ' ')
304 s++;
305 }
306 else
307 r.Cat(*s++);
308 }
309 return r;
310 }
311
Dump() const312 String Parser::Context::Dump() const
313 {
314 return "Scopeing: " + scope;
315 }
316
317 static String s_dblcln("::");
318
ScopeCat(String & scope,const String & s)319 inline void ScopeCat(String& scope, const String& s)
320 {
321 if(scope.GetCount())
322 scope << s_dblcln;
323 scope << s;
324 }
325
operator <<=(const Context & t)326 void Parser::Context::operator<<=(const Context& t)
327 {
328 ns = t.ns;
329 scope = t.scope;
330 typenames = clone(t.typenames);
331 tparam = clone(t.tparam);
332 access = t.access;
333 ctname = t.ctname;
334 namespace_using = t.namespace_using;
335 }
336
IsNamespace(const String & scope)337 bool Parser::IsNamespace(const String& scope)
338 {
339 int l = scope.GetCount();
340 return memcmp(~context.ns, ~scope, l) == 0 && findarg(context.ns[l], '\0', ':') >= 0;
341 }
342
Key(int code)343 bool Parser::Key(int code)
344 {
345 if(lex == code) {
346 ++lex;
347 return true;
348 }
349 return false;
350 }
351
GetLine(const char * p)352 int Parser::GetLine(const char *p)
353 {
354 int pos = int(p - ~file.text);
355 int l = 0;
356 int h = file.linepos.GetCount();
357 while(l < h) {
358 int q = (l + h) / 2;
359 if(file.linepos[q] < pos)
360 l = q + 1;
361 else
362 h = q;
363 }
364 return l;
365 }
366
Line()367 void Parser::Line()
368 {
369 int pos = int(lex.Pos() - ~file.text);
370 while(line + 1 < file.linepos.GetCount() && file.linepos[line + 1] <= pos)
371 line++;
372 }
373
Check(bool b,const char * err)374 void Parser::Check(bool b, const char *err)
375 {
376 if(!b) ThrowError(err);
377 }
378
CheckKey(int c)379 void Parser::CheckKey(int c)
380 {
381 if(!Key(c)) ThrowError(Format("Missing %c", c));
382 }
383
TemplateParams(String & param)384 String Parser::TemplateParams(String& param)
385 {
386 String r;
387 do {
388 const char *pos = lex.Pos();
389 CheckKey('<');
390 int level = 1;
391 String id;
392 bool gp = true;
393 while(lex != t_eof) {
394 if(lex.IsId() && gp)
395 id = lex.GetId();
396 else
397 if(Key(',')) {
398 ScAdd(param, id);
399 id.Clear();
400 gp = true;
401 }
402 else
403 if(Key('=')) {
404 if(!id.IsEmpty()) {
405 ScAdd(param, id);
406 id.Clear();
407 }
408 gp = false;
409 }
410 else
411 if(Key('>')) {
412 level--;
413 if(level <= 0) {
414 ScAdd(param, id);
415 break;
416 }
417 }
418 else
419 if(Key(t_shr) && level >= 2) {
420 level -= 2;
421 if(level <= 0) {
422 ScAdd(param, id);
423 break;
424 }
425 }
426 else
427 if(Key('<'))
428 level++;
429 else
430 if(Key('('))
431 level++;
432 else
433 if(Key(')'))
434 level--;
435 else
436 ++lex;
437 }
438 MergeWith(r, ",", String(pos, lex.Pos()));
439 }
440 while(Key(tk_template));
441 return r;
442 }
443
TemplateParams()444 String Parser::TemplateParams()
445 {
446 String dummy;
447 return TemplateParams(dummy);
448 }
449
TemplatePnames()450 String Parser::TemplatePnames()
451 {
452 String pnames;
453 TemplateParams(pnames);
454 return pnames;
455 }
456
ReadOper(bool & castoper)457 String Parser::ReadOper(bool& castoper) {
458 const char *p = lex.Pos();
459 Key(tk_operator);
460 int level = 0;
461 if(Key('('))
462 level++;
463 for(;;) {
464 if(lex == t_eof || level <= 0 && lex == '(') break;
465 if(Key('(') || Key('[')) level++;
466 else
467 if(Key(')') || Key(']')) level--;
468 else
469 ++lex;
470 }
471 StringBuffer r;
472 bool spc = false;
473 while(p < lex.Pos()) {
474 if((byte)*p > ' ') {
475 if(spc && iscid(*p)) {
476 castoper = true;
477 r.Cat(' ');
478 }
479 r.Cat(*p);
480 spc = false;
481 }
482 else
483 spc = true;
484 p++;
485 }
486 return String(r);
487 }
488
Name(String & name,bool & castoper,bool & oper)489 String Parser::Name(String& name, bool& castoper, bool& oper)
490 {
491 String s;
492 if(Key(t_dblcolon)) {
493 s = "::";
494 name = s;
495 }
496 Check(lex.IsId() || lex == tk_operator, "Name expected");
497 for(;;) {
498 if(lex.IsId()) {
499 name << lex.Id();
500 s << lex.GetId();
501 }
502 else {
503 String h = ReadOper(castoper);
504 oper = true;
505 name << h;
506 s << h;
507 break;
508 }
509 if(lex == '<') // void Fn<byte>(); situation
510 s << TemplateParams();
511 if(Key(t_dblcolon)) {
512 s << "::";
513 name << "::";
514 if(Key('~')) {
515 s << "~";
516 name << "~";
517 }
518 }
519 else
520 break;
521 }
522 return s;
523 }
524
Name(bool & castoper,bool & oper)525 String Parser::Name(bool& castoper, bool& oper)
526 {
527 String h;
528 return Name(h, castoper, oper);
529 }
530
Constant()531 String Parser::Constant()
532 {
533 const char *p = lex.Pos();
534 const char *p1 = p;
535 int level = 0;
536 for(;;) {
537 p1 = lex.Pos();
538 if(lex == t_eof) break;
539 if(level <= 0 && (lex == ',' || lex == ';' || lex == ')' || lex == '}' || lex == ']'))
540 break;
541 if(Key('(') || Key('[') || Key('{')) level++;
542 else
543 if(Key(')') || Key(']') || Key('}')) level--;
544 else
545 ++lex;
546 }
547 return String(p, p1);
548 }
549
TType()550 String Parser::TType()
551 {
552 int q = FindIndex(context.tparam, lex[0]);
553 if(q >= 0) return AsString(q);
554 return lex.Id();
555 }
556
StructDeclaration(const String & tn,const String & tp)557 String Parser::StructDeclaration(const String& tn, const String& tp)
558 {
559 int t = lex.GetCode(); // t is now struct/class/union
560 context.typenames.FindAdd(lex);
561 Context cc;
562 cc <<= context;
563 CParser p(tp);
564 Vector<String> tpar;
565 if(p.Char('<')) {
566 while(!p.IsEof() && !p.Char('>')) {
567 if((p.Id("class") || p.Id("typename") || p.Id("struct")) && p.IsId()) {
568 tpar.Add(p.ReadId());
569 context.tparam.Add(lex.Id(tpar.Top()));
570 }
571 else
572 context.tparam.Add(0);
573 TpSkip(p);
574 p.Char(',');
575 }
576 }
577 if(Key(t_dblcolon))
578 context.scope = Null;
579 String name;
580 String new_scope = context.scope;
581 if(lex.IsId())
582 do {
583 context.typenames.FindAdd(lex);
584 name = lex.GetId(); // name of structure
585 if(lex == '<')
586 name << TemplateParams();
587 ScopeCat(new_scope, name);
588 }
589 while(Key(t_dblcolon));
590 else {
591 name = AnonymousName();
592 ScopeCat(new_scope, name);
593 }
594 if(lex.IsId() && findarg(lex.Id(), "override", "final") >= 0)
595 ++lex;
596 if(lex.IsId() || lex == '*') { // struct My { struct My *p; }
597 return name;
598 }
599 context.scope = new_scope;
600 context.access = t == tk_class ? PRIVATE : PUBLIC;
601 if(tn.GetCount()) {
602 if(context.ctname.GetCount())
603 context.ctname << ';';
604 context.ctname << tn;
605 }
606 String nn;
607 if(!tp.IsEmpty())
608 nn = "template " + tp + " ";
609 String key = (t == tk_class ? "class" : t == tk_union ? "union" : "struct");
610 nn << key << ' ' << name;
611 LLOG("Struct " << context.scope << " using " << context.namespace_using);
612 CppItem& im = Item(context.scope, context.namespace_using, key, name, lex != ';');
613 im.kind = tp.IsEmpty() ? STRUCT : STRUCTTEMPLATE;
614 im.type = name;
615 im.access = cc.access;
616 im.tname = tn;
617 im.ctname = context.ctname;
618 im.tparam = CleanTp(tp);
619 im.ptype.Clear();
620 im.pname.Clear();
621 im.param.Clear();
622 if(lex == ';') { // TODO: perhaps could be united with following code
623 context = pick(cc);
624 im.natural = Gpurify(nn);
625 SetScopeCurrent();
626 return name;
627 }
628 if(Key(':')) {
629 nn << " : ";
630 bool c = false;
631 do {
632 String access = t == tk_class ? "private" : "public";
633 bool virt = Key(tk_virtual);
634 if(Key(tk_public)) access = "public";
635 else
636 if(Key(tk_protected)) access = "protected";
637 else
638 if(Key(tk_private)) access = "private";
639 if(Key(tk_virtual) || virt) access << " virtual";
640 String h;
641 bool dummy;
642 String n = Name(h, dummy, dummy);
643 ScAdd(im.pname, h);
644 if(c)
645 im.ptype << ';';
646 im.ptype << Subst(n, tpar);
647 ScAdd(im.param, access + ' ' + n);
648 if(c)
649 nn << ", ";
650 nn << access + ' ' + n;
651 c = true;
652 }
653 while(Key(','));
654 }
655 if(Key('{')) {
656 struct_level++;
657 ScopeBody();
658 struct_level--;
659 im.natural = Gpurify(nn);
660 im.decla = true;
661 }
662 else
663 if(IsNull(im.natural))
664 im.natural = Gpurify(nn);
665 context = pick(cc);
666 SetScopeCurrent();
667 return name;
668 }
669
ReadType(Decla & d,const String & tname,const String & tparam)670 String Parser::ReadType(Decla& d, const String& tname, const String& tparam)
671 { // returns the name of constructor
672 if(findarg((int)lex, tk_struct, tk_class, tk_union) >= 0 && !d.isfriend) {
673 d.type = StructDeclaration(tname, tparam);
674 return String();
675 }
676 Key(tk_typename) || Key(tk_struct) || Key(tk_class) || Key(tk_union) || Key(tk_enum) || Key(tk_template);
677 if(Key(tk_bool) || Key(tk_float) || Key(tk_double) || Key(tk_void))
678 return Null;
679 bool sgn = Key(tk_signed) || Key(tk_unsigned);
680 if(Key(tk_long)) {
681 Key(tk_long);
682 Key(tk_int) || Key(tk_double);
683 return Null;
684 }
685 if(Key(tk_short)) {
686 Key(tk_unsigned);
687 Key(tk_int);
688 return Null;
689 }
690 if(Key(tk_int) || Key(tk_char) ||
691 Key(tk___int8) || Key(tk___int16) || Key(tk___int32) || Key(tk___int64) || Key(tk___int128) ||
692 Key(tk_char16_t) || Key(tk_char32_t)) return Null;
693 if(sgn) return Null;
694 const char *p = lex.Pos();
695 bool cs = false;
696 Index<int> cix;
697 if(Key(tk_decltype) && Key('(')) {
698 const char *p = lex.Pos();
699 int lvl = 1;
700 for(;;) {
701 if(lex == t_eof)
702 break;
703 if(lex == '(')
704 lvl++;
705 else
706 if(lex == ')' && --lvl == 0) {
707 d.type = "@" + String(p, lex.Pos());
708 ++lex;
709 break;
710 }
711 ++lex;
712 }
713 }
714 else
715 if(Key(tk_auto))
716 d.type = "*";
717 else {
718 if(Key(t_dblcolon))
719 d.type << "::";
720 Key(tk_typename) || Key(tk_template);
721 Check(lex.IsId(), "Name expected");
722 while(lex.IsId()) {
723 d.type << TType();
724 if(cix.Find(lex) >= 0)
725 cs = true;
726 else
727 cix.Add(lex);
728 ++lex;
729 if(lex == '<')
730 d.type << TemplateParams();
731 if(Key(t_dblcolon)) {
732 d.type << "::";
733 if(Key('~'))
734 cs = true;
735 Key(tk_typename) || Key(tk_template);
736 }
737 else
738 break;
739 }
740 }
741 return cs ? String(p, lex.Pos()) : String();
742 }
743
Qualifier(bool override_final)744 void Parser::Qualifier(bool override_final)
745 {
746 for(;;)
747 if(Key(tk_const) || Key(tk_volatile) || Key(tk_constexpr) || Key(tk_thread_local) || VCAttribute())
748 ;
749 else
750 if(Key(tk_noexcept)) {
751 if(Key('(')) {
752 int lvl = 0;
753 while(lex != t_eof && lex != ';' && !(lvl == 0 && Key(')')))
754 if(Key('('))
755 lvl++;
756 else
757 if(Key(')'))
758 lvl--;
759 else
760 ++lex;
761 }
762 }
763 else
764 if(override_final && lex.IsId() && findarg(lex.Id(), "override", "final") >= 0)
765 ++lex;
766 else
767 if(Key(tk_throw) || Key(tk_alignas)) {
768 while(lex != t_eof && lex != ';' && !Key(')'))
769 ++lex;
770 }
771 else
772 if(lex[0] == '=' && findarg(lex[1], tk_delete, tk_default) >= 0) {
773 ++lex;
774 ++lex;
775 }
776 else
777 break;
778 }
779
Elipsis(Decl & d)780 void Parser::Elipsis(Decl& d)
781 {
782 Decl& q = d.param.Add();
783 q.name = "...";
784 if(lex.IsId()) // bool emplace(_Args&&... __args);
785 ++lex;
786 CheckKey(')');
787 }
788
ParamList(Decl & d)789 void Parser::ParamList(Decl& d) {
790 if(!Key(')'))
791 for(;;) {
792 if(Key(t_elipsis)) {
793 Elipsis(d);
794 break;
795 }
796 else {
797 Array<Parser::Decl> decl = Declaration(false, false, Null, Null);
798 if(decl.GetCount()) {
799 d.param.Add() = pick(decl.Top());
800 if(dobody) { // put arguments to the list of local variables
801 Decl& p = d.param.Top();
802 Local& l = local.Add(p.name);
803 l.type = p.type;
804 l.isptr = p.isptr;
805 l.line = line + 1;
806 }
807 }
808 }
809 if(Key(t_elipsis)) {
810 Elipsis(d);
811 break;
812 }
813 if(Key(')')) break;
814 CheckKey(',');
815 }
816 }
817
RPtr()818 int Parser::RPtr()
819 {
820 int n = 0;
821 int tlevel = 0;
822 for(;;) {
823 int t = lex[n];
824 if(t == '*') return n + 1;
825 if(t == '<') {
826 tlevel++;
827 n++;
828 }
829 else
830 if(t == '>') {
831 tlevel--;
832 n++;
833 }
834 else
835 if(t == t_shr && tlevel >= 2) {
836 tlevel -= 2;
837 n++;
838 }
839 else
840 if(t == t_dblcolon || lex.IsId(n) || t == ',' && tlevel > 0)
841 n++;
842 else
843 return 0;
844 }
845 }
846
EatInitializers()847 void Parser::EatInitializers()
848 {
849 if(Key(':')) {
850 int lvl = 0;
851 for(;;) {
852 if(lex == t_eof)
853 break;
854 if(lvl == 0) {
855 Qualifier(false);
856 if(lex == '{')
857 break;
858 if(lex.IsId() && lex[1] == '{') { // : X{123} { case
859 lvl++;
860 ++lex;
861 ++lex;
862 }
863 }
864 else
865 if(lex == '{')
866 lvl++;
867 if(lex == '(')
868 lvl++;
869 if(lex == ')' || lex == '}')
870 lvl--;
871 ++lex;
872 }
873 }
874 }
875
Declarator(Decl & d,const char * p)876 void Parser::Declarator(Decl& d, const char *p)
877 {
878 int n = RPtr();
879 if(n) {
880 while(n--) lex.Get();
881 Declarator(d, p);
882 d.isptr = true;
883 return;
884 }
885 if(Key('&') || Key(t_and) || Key(tk_const) || Key(tk_volatile)) { // t_and is r-value here
886 Declarator(d, p);
887 return;
888 }
889 if(Key('(')) {
890 Declarator(d, p);
891 if(d.isptr)
892 d.nofn = true;
893 CheckKey(')');
894 }
895 // if(lex == tk_operator)
896 // d.name = ReadOper();
897 // else
898 if(lex.IsId() || lex == t_dblcolon || lex == tk_operator) {
899 d.name = Name(d.castoper, d.oper);
900 if(lex == ':' && lex[1] == t_integer) { // Bitfield, like 'unsigned x:5'
901 ++lex;
902 ++lex;
903 }
904 }
905 if(Key('(')) {
906 if(inbody || (lex < 256 || lex == tk_true || lex == tk_false)
907 && lex != ')' && lex != '[' && lex != t_dblcolon) {
908 int level = 0;
909 for(;;) {
910 if(lex == t_eof) break;
911 if(Key('(')) level++;
912 else
913 if(Key(')')) {
914 if(--level < 0) break;
915 }
916 else
917 ++lex;
918 }
919 return;
920 }
921 else {
922 d.function = !d.nofn;
923 ParamList(d);
924 p = lex.Pos();
925 Qualifier(true);
926
927 if(d.function && Key(t_arrow)) { // C++11 trailing return type
928 d.type.Clear();
929 ReadType(d, Null, Null);
930 }
931
932 if(filetype == FILE_C && lex != '{' && lex != ';') // K&R style function header
933 while(lex != '{' && lex != t_eof)
934 ++lex;
935 }
936 }
937 if(*d.type == '*') // C++11 auto declaration
938 d.type = ResolveAutoType();
939 else
940 EatInitializers();
941 while(Key('[')) {
942 d.isptr = true;
943 int level = 1;
944 while(level && lex != t_eof) {
945 if(Key('[')) level++;
946 else
947 if(Key(']')) level--;
948 else
949 ++lex;
950 }
951 }
952 if(Key('=') || (inbody && lex == '(')) { // TODO: Add C++11 initializers here (?)
953 int level = 0;
954 int tlevel = 0;
955 for(;;) {
956 TryLambda();
957 if(lex == t_eof || lex == ';'
958 || level == 0 && ((lex == ',' && tlevel == 0) || lex == ')'))
959 break;
960 if(Key('<')) // we ignore < > as operators, always consider them template bracket
961 tlevel++;
962 else
963 if(Key('>'))
964 tlevel--;
965 else
966 if(Key('(') || Key('{'))
967 level++;
968 else
969 if(Key(')') || Key('}'))
970 level--;
971 else
972 ++lex;
973 }
974 }
975 }
976
Finish(Decl & d,const char * s)977 Parser::Decl& Parser::Finish(Decl& d, const char *s)
978 {
979 d.natural = String(s, lex.Pos());
980 return d;
981 }
982
IsParamList(int q)983 bool Parser::IsParamList(int q)
984 {
985 return true;
986 }
987
ReadMods(Decla & d)988 void Parser::ReadMods(Decla& d)
989 {
990 for(;;) {
991 if(Key(tk_static))
992 d.s_static = true;
993 else
994 if(Key(tk_extern))
995 d.s_extern = true;
996 else
997 if(Key(tk_register))
998 d.s_register = true;
999 else
1000 if(Key(tk_mutable))
1001 d.s_mutable = true;
1002 else
1003 if(Key(tk_explicit))
1004 d.s_explicit = true;
1005 else
1006 if(Key(tk_virtual))
1007 d.s_virtual = true;
1008 else
1009 if(!(Key(tk_inline) || Key(tk_force_inline) || Key(tk_never_inline) || Key(tk___inline) || VCAttribute()))
1010 break;
1011 }
1012 }
1013
Declaration0(bool l0,bool more,const String & tname,const String & tparam)1014 Array<Parser::Decl> Parser::Declaration0(bool l0, bool more, const String& tname, const String& tparam)
1015 {
1016 Array<Decl> r;
1017 Decla d;
1018 const char *p = lex.Pos();
1019 if(Key(tk_friend))
1020 d.isfriend = true;
1021 ReadMods(d);
1022 Qualifier();
1023 if(l0) {
1024 if(lex == tk_SKYLARK && lex[1] == '(' && lex.IsId(2)) {
1025 ++lex;
1026 ++lex;
1027 Decl& a = r.Add();
1028 a.name = lex.GetId();
1029 a.function = true;
1030 a.natural = String().Cat() << "void " << a.name << "(Http& http)";
1031 Decl& p = a.param.Add();
1032 p.name = "http";
1033 p.type = "Http";
1034 p.natural = "Http& http";
1035 Key(',');
1036 lex.GetText();
1037 Key(')');
1038 return r;
1039 }
1040 else
1041 if((lex == tk_RPC_METHOD || lex == tk_RPC_GMETHOD) && lex[1] == '(' && lex.IsId(2)) {
1042 ++lex;
1043 ++lex;
1044 Decl& a = r.Add();
1045 a.name = lex.GetId();
1046 a.function = true;
1047 a.natural = String().Cat() << "void " << a.name << "(RpcData& rpc)";
1048 Decl& p = a.param.Add();
1049 p.name = "rpc";
1050 p.type = "RpcData";
1051 p.natural = "RpcData& rpc";
1052 if (Key(','))
1053 lex.GetText();
1054 Key(')');
1055 return r;
1056 }
1057 }
1058 bool isdestructor = Key('~');
1059 if(l0 && context.typenames.Find(lex) >= 0 && lex[1] == '(' && lex.IsId()) {
1060 Decl& a = r.Add();
1061 a.name = lex.GetId();
1062 a.isdestructor = isdestructor;
1063 a.function = true;
1064 a.istructor = true;
1065 ++lex;
1066 ParamList(a);
1067 Qualifier();
1068 a.natural = String(p, lex.Pos());
1069 EatInitializers();
1070 return r;
1071 }
1072 if(lex == tk_operator) {
1073 Decl& a = r.Add();
1074 (Decla&)a = d;
1075 a.name = ReadOper(a.castoper);
1076 Key('(');
1077 ParamList(a);
1078 Qualifier();
1079 a.function = true;
1080 a.natural = String(p, lex.Pos());
1081 a.oper = true;
1082 return r;
1083 }
1084 String st = ReadType(d, tname, tparam);
1085 if(!lex.IsGrounded()) // 'static' etc.. can be after type too... (but not allow it on start of line)
1086 ReadMods(d);
1087 if(!st.IsEmpty()) {
1088 Decl& a = r.Add();
1089 int q = st.Find('~');
1090 if(q >= 0)
1091 st.Remove(q, 1);
1092 a.name = st;
1093 a.isdestructor = q >= 0;
1094 a.function = true;
1095 a.istructor = true;
1096 if(Key('('))
1097 ParamList(a);
1098 Qualifier();
1099 a.natural = String(p, lex.Pos());
1100 EatInitializers();
1101 return r;
1102 }
1103 String natural1 = String(p, lex.Pos());
1104 if(lex != ';') // struct/class declaration without defining variable
1105 do {
1106 const char *p1 = lex.Pos();
1107 Decl& a = r.Add();
1108 (Decla&)a = d;
1109 Declarator(a, p);
1110 if(a.castoper)
1111 a.name = Filter(natural1, CharFilterNotWhitespace) + a.name;
1112 a.natural = natural1 + String(p1, lex.Pos());
1113 p = lex.Pos();
1114 }
1115 while(more && Key(','));
1116 return r;
1117 }
1118
Declaration(bool l0,bool more,const String & tname,const String & tparam)1119 Array<Parser::Decl> Parser::Declaration(bool l0, bool more, const String& tname, const String& tparam)
1120 {
1121 if(Key(tk_typedef)) {
1122 Array<Decl> r = Declaration0(false, true, tname, tparam);
1123 for(int i = 0; i < r.GetCount(); i++) {
1124 r[i].type_def = true;
1125 r[i].natural = "typedef " + r[i].natural;
1126 }
1127 return r;
1128 }
1129 const char *b = lex.Pos();
1130 if(Key(tk_using) && lex.IsId()) {
1131 String name = lex.GetId();
1132 Key('=');
1133 Array<Decl> r;
1134 Decl& d = r.Add();
1135 ReadType(d, tname, tparam);
1136 while(Key('*') || Key(tk_volatile) || Key(tk_const));
1137 d.name = name;
1138 d.natural = String(b, lex.Pos());
1139 d.type_def = true;
1140 return r;
1141 }
1142 return Declaration0(l0, more, tname, tparam);
1143 }
1144
Tparam(int & q)1145 String Parser::Tparam(int& q)
1146 {
1147 if(lex[q] != '<')
1148 return Null;
1149 const char *p = lex.Pos(q);
1150 int level = 1;
1151 q++;
1152 while(lex[q] != t_eof && level) {
1153 if(lex[q] == '<')
1154 level++;
1155 if(lex[q] == '>')
1156 level--;
1157 else
1158 if(lex[q] == t_shr && level >= 2)
1159 level -= 2;
1160 q++;
1161 }
1162 return String(p, lex.Pos(q));
1163 }
1164
NoTemplatePars(const String & s)1165 String NoTemplatePars(const String& s)
1166 {
1167 int q = s.Find('<');
1168 return q >= 0 ? s.Mid(0, q) : s;
1169 }
1170
VCAttribute()1171 bool Parser::VCAttribute()
1172 {
1173 if(lex[0] == '[') // Skip Visual C++ attribute
1174 for(;;) {
1175 if(lex[0] == ']') {
1176 ++lex;
1177 return true;
1178 }
1179 if(lex[0] == t_eof)
1180 return false;
1181 ++lex;
1182 }
1183 return false;
1184 }
1185
SetScopeCurrent()1186 void Parser::SetScopeCurrent()
1187 {
1188 current_scope = context.scope;
1189 }
1190
Item(const String & scope,const String & using_namespace,const String & item,const String & name,bool impl)1191 CppItem& Parser::Item(const String& scope, const String& using_namespace, const String& item,
1192 const String& name, bool impl)
1193 {
1194 current_scope = scope;
1195 if(dobody)
1196 current = CppItem();
1197 current_key = item;
1198 current_name = name;
1199 CppItem& im = dobody ? current : base->GetAdd(current_scope).Add();
1200 im.item = item;
1201 im.name = name;
1202 im.file = filei;
1203 im.line = line + 1;
1204 im.impl = impl;
1205 im.filetype = filetype;
1206 im.using_namespaces = using_namespace;
1207 LLOG("New item " << line + 1 << " " << scope << "::" << item);
1208 return im;
1209 }
1210
AddMacro(int lineno,const String & macro)1211 void Parser::AddMacro(int lineno, const String& macro)
1212 {
1213 String name;
1214 const char *s = macro;
1215 while(*s && iscid(*s))
1216 name.Cat(*s++);
1217 CppItem& im = Item("", "", macro, name);
1218 im.kind = MACRO;
1219 im.line = lineno;
1220 im.access = PUBLIC;
1221 }
1222
Item(const String & scope,const String & using_namespace,const String & item,const String & name)1223 CppItem& Parser::Item(const String& scope, const String& using_namespace, const String& item,
1224 const String& name)
1225 {
1226 String h = Purify(item);
1227 CppItem& im = Item(scope, using_namespace, h, name, false);
1228 im.natural = h;
1229 return im;
1230 }
1231
Resume(int bl)1232 void Parser::Resume(int bl)
1233 {
1234 for(;;) {
1235 if(lex == t_eof || lex.GetBracesLevel() == bl && lex == ';')
1236 break;
1237 ++lex;
1238 }
1239 }
1240
ScopeBody()1241 void Parser::ScopeBody()
1242 {
1243 int bl = lex.GetBracesLevel();
1244 while(!Key('}')) {
1245 if(lex == t_eof)
1246 ThrowError("Unexpected end of file");
1247 try {
1248 Do();
1249 }
1250 catch(Error) {
1251 Resume(bl);
1252 Key(';');
1253 }
1254 }
1255 }
1256
AnonymousName()1257 String Parser::AnonymousName()
1258 {
1259 int lvl = 0;
1260 for(int i = 0; lex[i] != t_eof; i++) {
1261 if(lex[i] == '{') lvl++;
1262 else
1263 if(lex[i] == '}')
1264 if(--lvl == 0) {
1265 if(lex.IsId(i + 1))
1266 return "." + lex.Id(i + 1);
1267 break;
1268 }
1269 }
1270
1271 dword x[4];
1272 x[0] = Random();
1273 x[1] = Random();
1274 x[2] = Random();
1275 x[3] = Random();
1276
1277 return "@" + Base64Encode(String((const char *)&x, sizeof(x))) + "/" + title;
1278 }
1279
AddNamespace(const String & n,const String & name)1280 void Parser::AddNamespace(const String& n, const String& name)
1281 {
1282 String h = "namespace " + n;
1283 CppItem& m = Item(n, Null, h, name);
1284 m.kind = NAMESPACE;
1285 m.natural = h;
1286 }
1287
Scope(const String & tp,const String & tn)1288 bool Parser::Scope(const String& tp, const String& tn) {
1289 if(Key(tk_namespace)) {
1290 Check(lex.IsId(), "Expected name of namespace");
1291 String name = lex.GetId();
1292 LLOG("namespace " << name);
1293 namespace_info << ';' << name;
1294 Context c0;
1295 c0 <<= context;
1296 int struct_level0 = struct_level;
1297 ScopeCat(context.scope, name);
1298 ScopeCat(context.ns, name);
1299 AddNamespace(context.scope, name);
1300 if(Key('{')) {
1301 Context cc;
1302 cc <<= context;
1303 while(!Key('}')) {
1304 if(lex == t_eof)
1305 ThrowError("Unexpected end of file");
1306 try {
1307 Do();
1308 }
1309 catch(Error) {
1310 if(struct_level0)
1311 throw;
1312 context <<= cc;
1313 struct_level = struct_level0;
1314 LLOG("---- Recovery to namespace level");
1315 ++lex;
1316 lex.SkipToGrounding();
1317 lex.ClearBracesLevel();
1318 LLOG("Grounding skipped to " << GetLine(lex.Pos()));
1319 }
1320 catch(Lex::Grounding) {
1321 LLOG("---- Grounding to namespace level");
1322 context <<= cc;
1323 struct_level = struct_level0;
1324 lex.ClearBracesLevel();
1325 lex.ClearBody();
1326 }
1327 }
1328 }
1329 LLOG("End namespace");
1330 Key(';');
1331 context <<= c0;
1332 SetScopeCurrent();
1333 namespace_info << ";}";
1334 return true;
1335 }
1336 return false;
1337 }
1338
Fn(const Decl & d,const String & templ,bool body,const String & tname,const String & tparam)1339 CppItem& Parser::Fn(const Decl& d, const String& templ, bool body,
1340 const String& tname, const String& tparam)
1341 {
1342 String param;
1343 String pname;
1344 String ptype;
1345 for(int i = 0; i < d.param.GetCount(); i++) {
1346 const Decla& p = d.param[i];
1347 ScAdd(param, p.natural);
1348 if(i)
1349 ptype << ';';
1350 ptype << p.type;
1351 ScAdd(pname, p.name);
1352 }
1353 String nn0;
1354 String nm = d.name;
1355 int q;
1356 if(d.castoper) {
1357 q = d.name.ReverseFind(' ');
1358 q = q > 0 ? d.name.ReverseFind(':', q) : d.name.ReverseFind(':');
1359 }
1360 else
1361 q = d.name.ReverseFind(':');
1362 if(q >= 0) {
1363 nm = d.name.Mid(q + 1);
1364 if(q > 0)
1365 nn0 = d.name.Mid(0, q - 1);
1366 }
1367 String item = FnItem(d.natural, pname, d.name, nm, d.oper);
1368 String scope = context.scope;
1369 String nn;
1370 const char *s = nn0;
1371 int l = 0;
1372 while(*s) {
1373 if(*s == '<')
1374 l++;
1375 else
1376 if(*s == '>')
1377 l--;
1378 else
1379 if(l == 0)
1380 nn.Cat(*s);
1381 s++;
1382 }
1383 s = nn;
1384 while(*s == ':') s++;
1385 if(*s)
1386 ScopeCat(scope, s);
1387 CppItem& im = Item(scope, context.namespace_using, item, nm, body);
1388 im.natural.Clear();
1389 if(!IsNull(templ)) {
1390 im.natural = TrimRight(Gpurify(templ)) + ' ';
1391 im.at = im.natural.GetLength();
1392 }
1393 im.natural << Purify(d.natural, d.name, nm);
1394 im.kind = templ.GetCount() ? IsNamespace(scope) ? FUNCTIONTEMPLATE
1395 : d.s_static ? CLASSFUNCTIONTEMPLATE
1396 : INSTANCEFUNCTIONTEMPLATE
1397 : d.istructor ? (d.isdestructor ? DESTRUCTOR : CONSTRUCTOR)
1398 : d.isfriend ? INLINEFRIEND
1399 : IsNamespace(scope) ? FUNCTION
1400 : d.s_static ? CLASSFUNCTION
1401 : INSTANCEFUNCTION;
1402 im.param = param;
1403 im.pname = pname;
1404 im.ptype = ptype;
1405 im.access = context.access;
1406 im.virt = d.s_virtual;
1407 im.type = d.type;
1408 im.decla = true;
1409 im.tname = tname;
1410 im.tparam = tparam;
1411 im.ctname = context.ctname;
1412 LLOG("FnItem: " << scope << "::" << item << ", natural: " << im.natural
1413 << ", ctname: " << im.ctname);
1414 return im;
1415 }
1416
Enum(bool vars)1417 void Parser::Enum(bool vars)
1418 {
1419 String name;
1420 if(lex.IsId())
1421 name = lex.GetId();
1422 while(lex != '{' && lex != ';' && lex != t_eof)
1423 ++lex;
1424 if(Key('{')) {
1425 for(;;) {
1426 Line();
1427 String val;
1428 Check(lex.IsId(), "Expected identifier");
1429 String id = lex.GetId();
1430 CppItem& im = Item(context.scope, context.namespace_using, id, id);
1431 im.natural = "enum ";
1432 if(!IsNull(name))
1433 im.natural << name << ' ';
1434 im.natural << id;
1435 if(Key('='))
1436 im.natural << " = " << Constant();
1437 im.kind = ENUM;
1438 im.access = context.access;
1439 Key(',');
1440 if(Key('}')) break;
1441 }
1442 }
1443 while(!Key(';')) {
1444 if(lex.IsId()) {
1445 if(vars) { // typedef name ignored here
1446 String scope = context.scope;
1447 String name = lex.GetId();
1448 CppItem& im = Item(scope, context.namespace_using, name, name);
1449 im.natural = "enum " + name;
1450 im.access = context.access;
1451 im.kind = IsNamespace(scope) ? VARIABLE : INSTANCEVARIABLE;
1452 }
1453 ++lex;
1454 }
1455 else
1456 if(lex == ',' || lex == '*')
1457 ++lex;
1458 else
1459 break;
1460 }
1461 Key(';');
1462 SetScopeCurrent();
1463 }
1464
UsingNamespace()1465 bool Parser::UsingNamespace()
1466 {
1467 if(lex == tk_using && !(lex.IsId(1) && lex[2] == '=')) {
1468 ++lex;
1469 if(Key(tk_namespace))
1470 while(lex.IsId()) {
1471 Vector<String> h = Split(context.namespace_using, ';');
1472 String u;
1473 do {
1474 u << lex.GetId();
1475 if(Key(t_dblcolon))
1476 u << "::";
1477 }
1478 while(lex.IsId());
1479 if(FindIndex(h, u) < 0)
1480 h.Add(u);
1481 context.namespace_using = Join(h, ";");
1482 Key(',');
1483 }
1484 while(!Key(';') && lex != t_eof)
1485 ++lex;
1486 namespace_info << ";using " << context.namespace_using;
1487 return true;
1488 }
1489 return false;
1490 }
1491
IsEnum(int i)1492 bool Parser::IsEnum(int i)
1493 {
1494 for(;;) {
1495 if(lex[i] == '{')
1496 return true;
1497 else
1498 if(lex.IsId(i) || lex[i] == ':' ||
1499 findarg(lex[i], tk_bool, tk_signed, tk_unsigned, tk_long, tk_int, tk_short,
1500 tk_char, tk___int8, tk___int16, tk___int32, tk___int64,
1501 tk_char16_t, tk_char32_t) >= 0)
1502 i++;
1503 else
1504 return false;
1505 }
1506 }
1507
ClassEnum()1508 void Parser::ClassEnum()
1509 {
1510 context.typenames.FindAdd(lex);
1511 Context cc;
1512 cc <<= context;
1513 String name = lex.GetId();
1514 String new_scope = context.scope;
1515 ScopeCat(new_scope, name);
1516 context.scope = new_scope;
1517 context.access = PUBLIC;
1518 String key = "class";
1519 LLOG("enum class " << context.scope << " using " << context.namespace_using);
1520 CppItem& im = Item(context.scope, context.namespace_using, key, name, lex != ';');
1521 im.kind = STRUCT;
1522 im.type = name;
1523 im.access = cc.access;
1524 im.tname.Clear();
1525 im.ctname.Clear();
1526 im.tparam.Clear();
1527 im.ptype.Clear();
1528 im.pname.Clear();
1529 im.param.Clear();
1530 Enum(true);
1531 context = pick(cc);
1532 SetScopeCurrent();
1533 }
1534
DoNamespace()1535 void Parser::DoNamespace()
1536 {
1537 if(Key('{'))
1538 while(!Key('}')) {
1539 if(lex == t_eof)
1540 ThrowError("Unexpected end of file");
1541 Do();
1542 }
1543 Key(';');
1544 }
1545
Do()1546 void Parser::Do()
1547 {
1548 LLOG("Do, scope: " << current_scope);
1549 if(lex.IsGrounded() && struct_level)
1550 throw Lex::Grounding();
1551 Line();
1552 if(UsingNamespace())
1553 ;
1554 else
1555 if(Key(tk_static_assert))
1556 while(lex != t_eof && lex != ';')
1557 ++lex;
1558 else
1559 if(lex == tk_inline && lex[1] == tk_namespace) { // for now, inline namespace is simply ignored
1560 while(lex != t_eof && lex != '{')
1561 ++lex;
1562 DoNamespace();
1563 }
1564 else
1565 if(Key(';')) // 'empty' declaration, result of some ignores
1566 ;
1567 else
1568 if(lex == tk_extern && lex[1] == tk_template) { // skip 'extern template void Foo<char>();'
1569 while(lex != t_eof) {
1570 if(lex == ';') {
1571 ++lex;
1572 break;
1573 }
1574 ++lex;
1575 }
1576 }
1577 else
1578 if(Key(tk_extern) && lex == t_string) { // extern "C++" kind
1579 ++lex;
1580 DoNamespace();
1581 }
1582 else
1583 if(Key(tk_template)) {
1584 if(lex.IsId() || lex == tk_class && lex.IsId(1)) {
1585 Key(tk_class);
1586 for(;;) {
1587 if(lex.IsId())
1588 lex.GetId();
1589 else
1590 if(!Key(t_dblcolon))
1591 break;
1592 }
1593 TemplateParams();
1594 Key(';');
1595 }
1596 else {
1597 String tnames;
1598 String tparam = TemplateParams(tnames);
1599 if(lex == tk_using) { //C++11 template alias template <...> using ID =
1600 Array<Decl> r = Declaration(true, true, tnames, tparam);
1601 for(int i = 0; i < r.GetCount(); i++) {
1602 Decla& d = r[i];
1603 if(d.type_def) {
1604 String scope = context.scope;
1605 ScopeCat(scope, d.name);
1606 CppItem& im = Item(scope, context.namespace_using, "typedef", d.name);
1607 im.natural = Purify(d.natural);
1608 im.type = d.type;
1609 im.access = context.access;
1610 im.kind = TYPEDEF;
1611 }
1612 }
1613 }
1614 else {
1615 if(!Scope(tparam, tnames)) {
1616 Array<Decl> r = Declaration(true, true, tnames, tparam);
1617 bool body = lex == '{';
1618 for(int i = 0; i < r.GetCount(); i++) {
1619 Decl& d = r[i];
1620 if(!d.isfriend && d.function)
1621 Fn(d, "template " + tparam + ' ', body, tnames, tparam);
1622 }
1623 EatBody();
1624 Key(';');
1625 }
1626 EatBody();
1627 }
1628 }
1629 }
1630 else
1631 if(lex == tk_enum && IsEnum(1)) {
1632 ++lex;
1633 Enum(true);
1634 }
1635 else
1636 if(lex == tk_enum && lex[1] == tk_class && IsEnum(2)) {
1637 ++lex;
1638 ++lex;
1639 ClassEnum(); // like enum class Foo { A, B }
1640 }
1641 else
1642 if(lex == tk_typedef && lex[1] == tk_enum && IsEnum(2)) {
1643 ++lex;
1644 ++lex;
1645 Enum(false);
1646 }
1647 else
1648 if(!Scope(String(), String())) {
1649 if(Key(tk_public)) {
1650 context.access = PUBLIC;
1651 Key(':');
1652 }
1653 else
1654 if(Key(tk_private)) {
1655 context.access = PRIVATE;
1656 Key(':');
1657 }
1658 else
1659 if(Key(tk_protected)) {
1660 context.access = PROTECTED;
1661 Key(':');
1662 }
1663 else {
1664 Array<Decl> r = Declaration(true, true, Null, Null);
1665 bool body = lex == '{';
1666 for(int i = 0; i < r.GetCount(); i++) {
1667 Decl& d = r[i];
1668 if(d.name.GetCount()) {
1669 if(d.function) {
1670 if(!d.isfriend)
1671 Fn(d, Null, body, String(), String());
1672 }
1673 else {
1674 String h = d.natural;
1675 int q = h.Find('=');
1676 if(q >= 0)
1677 h = TrimRight(h.Mid(0, q));
1678 String scope = context.scope;
1679 if(d.type_def)
1680 ScopeCat(scope, d.name);
1681 String name = d.name;
1682 int member_type = d.s_static ? CLASSVARIABLE : INSTANCEVARIABLE;
1683 q = d.name.ReverseFind("::");
1684 if(q >= 0) { // class variable definition like: int Ctrl::EventLoop;
1685 ScopeCat(scope, d.name.Mid(0, q));
1686 current_scope = scope; // temporary until ';'
1687 name = d.name.Mid(q + 2);
1688 member_type = CLASSVARIABLE;
1689 }
1690 CppItem& im = Item(scope, context.namespace_using,
1691 d.isfriend ? "friend class"
1692 : d.type_def ? "typedef"
1693 : name, name);
1694 im.natural = Purify(h);
1695 im.type = d.type;
1696 im.access = context.access;
1697 im.kind = d.isfriend ? FRIENDCLASS :
1698 d.type_def ? TYPEDEF :
1699 IsNamespace(scope) ? VARIABLE :
1700 member_type;
1701 if(im.IsData())
1702 im.isptr = d.isptr;
1703 }
1704 }
1705 }
1706 EatBody();
1707 if(Key(';'))
1708 SetScopeCurrent(); // need to be after ';' to make class variable definitions work
1709 }
1710 }
1711 }
1712
Do(Stream & in,CppBase & _base,int filei_,int filetype_,const String & title_,Event<int,const String &> _err,const Vector<String> & typenames,const Vector<String> & namespace_stack,const Index<String> & namespace_using)1713 void Parser::Do(Stream& in, CppBase& _base, int filei_, int filetype_,
1714 const String& title_, Event<int, const String&> _err,
1715 const Vector<String>& typenames,
1716 const Vector<String>& namespace_stack,
1717 const Index<String>& namespace_using)
1718 {
1719 LTIMING("Parser::Do");
1720 LLOG("= C++ Parser ==================================== " << title_ << " " << namespace_stack << ", dobody: " << dobody);
1721 base = &_base;
1722 err = _err;
1723 filei = filei_;
1724 filetype = filetype_;
1725 title = title_;
1726 lpos = 0;
1727 line = 0;
1728
1729 context.namespace_using = Join(namespace_using.GetKeys(), ";");
1730
1731 String n;
1732 for(int i = 0; i < namespace_stack.GetCount(); i++) {
1733 MergeWith(n, "::", namespace_stack[i]);
1734 AddNamespace(n, namespace_stack[i]);
1735 }
1736
1737 file = PreProcess(in, *this);
1738 lex.Init(~file.text);
1739
1740 while(lex != t_eof)
1741 try {
1742 try {
1743 current_scope.Clear();
1744 context.access = PUBLIC;
1745 context.typenames.Clear();
1746 context.tparam.Clear();
1747 context.ns = context.scope = Join(namespace_stack, "::");
1748 inbody = false;
1749 struct_level = 0;
1750 for(int i = 0; i < typenames.GetCount(); i++)
1751 context.typenames.Add(lex.Id(typenames[i]));
1752 Do();
1753 }
1754 catch(Error) {
1755 if(lex.IsBody()) {
1756 LLOG("---- Recovery to next ';'");
1757 Resume(lex.GetBracesLevel());
1758 Key(';');
1759 }
1760 else {
1761 LLOG("---- Recovery to file level");
1762 ++lex;
1763 lex.SkipToGrounding();
1764 lex.ClearBracesLevel();
1765 LLOG("Grounding skipped to " << GetLine(lex.Pos()));
1766 }
1767 }
1768 }
1769 catch(Lex::Grounding) {
1770 LLOG("---- Grounding to file level");
1771 lex.ClearBracesLevel();
1772 lex.ClearBody();
1773 }
1774 }
1775
GetNamespaces() const1776 Vector<String> ParserContext::GetNamespaces() const
1777 {
1778 Vector<String> ns;
1779 Vector<String> h = Split(current_scope, ':');
1780 while(h.GetCount()) {
1781 ns.Add(Join(h, "::"));
1782 h.Drop();
1783 }
1784 ns.Append(Split(context.namespace_using, ';'));
1785 ns.Add(""); // Add global namespace too
1786 return ns;
1787 }
1788
1789 }
1790