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