1 /**
2  * Copyright: Copyright (c) 2017 Wojciech Szęszoł. All rights reserved.
3  * Authors: Wojciech Szęszoł
4  * Version: Initial created: October 05, 2017
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dstep.translator.MacroParser;
8 
9 import std.array;
10 import std.meta;
11 import std.traits;
12 import std.variant;
13 import std.stdio;
14 
15 import clang.c.Index;
16 import clang.Cursor;
17 import clang.Token;
18 import clang.Type;
19 import clang.Util;
20 import clang.SourceLocation;
21 import clang.SourceRange;
22 
23 enum bool isStringValue(alias T) =
24     is(typeof(T) : const char[]) &&
25     !isAggregateType!(typeof(T)) &&
26     !isStaticArray!(typeof(T));
27 
28 /**
29  * The accept family of functions parse tokens. In the case of successful parsing,
30  * the function advances the beginning of the tokens to the next token and returns true.
31  *
32  * The parsing is successful, if the first token in tokens is of the specified kind
33  * and its spelling matches one of the strings passed as Args.
34  * It assigns the spelling of the token to the spelling parameter.
35  */
36 bool accept(Args...)(ref Token[] tokens, ref string spelling, TokenKind kind)
37     if (Args.length > 0 && allSatisfy!(isStringValue, Args))
38 {
39     if (!tokens.empty && tokens.front.kind == kind)
40     {
41         foreach (arg; Args)
42         {
43             if (tokens.front.spelling == arg)
44             {
45                 tokens = tokens[1 .. $];
46                 spelling = arg;
47                 return true;
48             }
49         }
50     }
51 
52     return false;
53 }
54 
55 bool accept(ref Token[] tokens, ref string spelling, TokenKind kind)
56 {
57     if (!tokens.empty && tokens.front.kind == kind)
58     {
59         spelling = tokens.front.spelling;
60         tokens = tokens[1 .. $];
61         return true;
62     }
63 
64     return false;
65 }
66 
67 bool accept(Args...)(ref Token[] tokens, TokenKind kind)
68     if (allSatisfy!(isStringValue, Args))
69 {
70     if (!tokens.empty && tokens.front.kind == kind)
71     {
72         foreach (arg; Args)
73         {
74             if (tokens.front.spelling == arg)
75             {
76                 tokens = tokens[1 .. $];
77                 return true;
78             }
79         }
80     }
81 
82     return false;
83 }
84 
85 bool accept(Args...)(ref Token[] tokens, ref string spelling)
86     if (Args.length > 0 && allSatisfy!(isStringValue, Args))
87 {
88     if (!tokens.empty)
89     {
90         foreach (arg; Args)
91         {
92             if (tokens.front.spelling == arg)
93             {
94                 tokens = tokens[1 .. $];
95                 spelling = arg;
96                 return true;
97             }
98         }
99     }
100 
101     return false;
102 }
103 
104 bool acceptPunctuation(Args...)(ref Token[] tokens, ref string spelling)
105     if (allSatisfy!(isStringValue, Args))
106 {
107     return accept!(Args)(tokens, spelling, TokenKind.punctuation);
108 }
109 
110 bool acceptPunctuation(Args...)(ref Token[] tokens)
111     if (allSatisfy!(isStringValue, Args))
112 {
113     return accept!(Args)(tokens, TokenKind.punctuation);
114 }
115 
116 bool acceptIdentifier(ref Token[] tokens, ref string spelling)
117 {
118     return accept(tokens, spelling, TokenKind.identifier);
119 }
120 
121 bool acceptLiteral(ref Token[] tokens, ref string spelling)
122 {
123     return accept(tokens, spelling, TokenKind.literal);
124 }
125 
126 bool acceptKeyword(ref Token[] tokens, ref string spelling)
127 {
128     return accept(tokens, spelling, TokenKind.keyword);
129 }
130 
131 bool acceptStringLiteral(ref Token[] tokens, ref string spelling)
132 {
133     import std..string : startsWith, endsWith;
134 
135     if (!tokens.empty && tokens.front.kind == TokenKind.literal)
136     {
137         spelling = tokens.front.spelling;
138 
139         if (!spelling.startsWith(`"`) || !spelling.endsWith(`"`))
140             return false;
141 
142         tokens = tokens[1 .. $];
143         return true;
144     }
145 
146     return false;
147 }
148 
149 Expression parseLeftAssoc(ResultExpr, alias parseChild, Ops...)(
150     ref Token[] tokens,
151     Cursor[string] table,
152     bool defined) if (allSatisfy!(isStringValue, Ops))
153 {
154     import std.traits;
155     import std.range;
156 
157     auto local = tokens;
158 
159     ReturnType!parseChild[] exprs = [ parseChild(local, table, defined) ];
160     string[] ops = [];
161 
162     if (!exprs[0].hasValue)
163         return Expression.init;
164 
165     string op;
166     while (accept!(Ops)(local, op, TokenKind.punctuation))
167     {
168         exprs ~= parseChild(local, table, defined);
169 
170         if (!exprs[$ - 1].hasValue)
171             return Expression.init;
172 
173         ops ~= op;
174     }
175 
176     tokens = local;
177 
178     if (exprs.length == 1)
179         return exprs[0];
180 
181     ResultExpr result = new ResultExpr;
182     result.left = exprs[0];
183     result.right = exprs[1];
184     result.operator = ops[0];
185 
186     foreach (expr, fop; zip(exprs[2 .. $], ops[1 .. $]))
187     {
188         ResultExpr parent = new ResultExpr;
189         parent.left = result;
190         parent.right = expr;
191         parent.operator = fop;
192         result = parent;
193     }
194 
195     return Expression(result);
196 }
197 
198 struct Identifier
199 {
200     string spelling;
201 
202     string toString()
203     {
204         import std.format : format;
205 
206         return format("Identifier(spelling = %s)", spelling);
207     }
208 }
209 
210 struct TypeIdentifier
211 {
212     Type type;
213 }
214 
215 struct Literal
216 {
217     string spelling;
218 
219     this (string spelling)
220     {
221         this.spelling = spelling;
222     }
223 
224     string toString()
225     {
226         import std.format : format;
227 
228         return format("Literal(spelling = %s)", spelling);
229     }
230 }
231 
232 struct StringLiteral
233 {
234     string spelling;
235 
236     this (string spelling)
237     {
238         this.spelling = spelling;
239     }
240 
241     string toString()
242     {
243         import std.format : format;
244 
245         return format("Literal(spelling = %s)", spelling);
246     }
247 }
248 
249 struct StringifyExpr
250 {
251     string spelling;
252 
253     this (string spelling)
254     {
255         this.spelling = spelling;
256     }
257 
258     string toString()
259     {
260         import std.format : format;
261 
262         return format("StringifyExpr(spelling = %s)", spelling);
263     }
264 }
265 
266 class StringConcat
267 {
268     Expression[] substrings;
269 
270     this (Expression[] substrings)
271     {
272         this.substrings = substrings;
273     }
274 
275     override string toString()
276     {
277         import std.format : format;
278 
279         return format("StringConcat(substrings = %s)", substrings);
280     }
281 }
282 
283 class TokenConcat
284 {
285     Expression[] subexprs;
286 
287     this (Expression[] subexprs)
288     {
289         this.subexprs = subexprs;
290     }
291 
292     override string toString()
293     {
294         import std.format : format;
295 
296         return format("TokenConcat(subexprs = %s)", subexprs);
297     }
298 }
299 
300 class IndexExpr
301 {
302     Expression subexpr;
303     Expression index;
304 
305     override string toString()
306     {
307         import std.format : format;
308 
309         return format("IndexExpr(subexpr = %s, index = %s)", subexpr, index);
310     }
311 }
312 
313 class CallExpr
314 {
315     Expression expr;
316     Expression[] args;
317 
318     override string toString()
319     {
320         import std.format : format;
321 
322         return format("CallExpr(expr = %s, args = %s)", expr, args);
323     }
324 }
325 
326 class DotExpr
327 {
328     Expression subexpr;
329     string identifier;
330 
331     override string toString()
332     {
333         import std.format : format;
334 
335         return format(
336             "DotExpr(subexpr = %s, identifier = %s)",
337             subexpr,
338             identifier);
339     }
340 }
341 
342 class ArrowExpr : DotExpr
343 {
344     override string toString()
345     {
346         import std.format : format;
347 
348         return format(
349             "ArrowExpr(subexpr = %s, identifier = %s)",
350             subexpr,
351             identifier);
352     }
353 }
354 
355 class SubExpr
356 {
357     Expression subexpr;
358 
359     this (Expression subexpr)
360     {
361         this.subexpr = subexpr;
362     }
363 
364     override string toString()
365     {
366         import std.format : format;
367 
368         return format("SubExpr(subexpr = %s)", subexpr);
369     }
370 }
371 
372 class UnaryExpr
373 {
374     Expression subexpr;
375     string operator;
376     bool postfix = false;
377 
378     override string toString()
379     {
380         import std.format : format;
381 
382         return format(
383             "UnaryExpr(subexpr = %s, operator = %s)",
384             subexpr,
385             operator);
386     }
387 }
388 
389 struct DefinedExpr
390 {
391     string identifier;
392 
393     string toString()
394     {
395         import std.format : format;
396 
397         return format("DefinedExpr(identifier = %s)", identifier);
398     }
399 }
400 
401 struct SizeofType
402 {
403     Type type;
404 
405     string toString()
406     {
407         import std.format : format;
408 
409         return format("SizeofType(type = %s)", type);
410     }
411 }
412 
413 class CastExpr
414 {
415     Type type;
416     Expression subexpr;
417 
418     override string toString()
419     {
420         import std.format : format;
421 
422         return format(
423             "CastExpr(typename = %s, subexpr = %s)",
424             type,
425             subexpr);
426     }
427 }
428 
429 class BinaryExpr
430 {
431     Expression left;
432     Expression right;
433     string operator;
434 
435     override string toString()
436     {
437         import std.format : format;
438         import std.range : retro;
439         import std.algorithm.searching : findSplit;
440         import std.array : array;
441 
442         auto rname = findSplit(this.classinfo.name.retro, ".")[0].array;
443 
444         return format(
445             "%s(left = %s, right = %s, operator = %s)",
446             rname.retro,
447             left,
448             right,
449             operator);
450     }
451 }
452 
453 class MulExpr : BinaryExpr
454 { }
455 
456 class AddExpr : BinaryExpr
457 { }
458 
459 class SftExpr : BinaryExpr
460 { }
461 
462 class RelExpr : BinaryExpr
463 { }
464 
465 class EqlExpr : BinaryExpr
466 { }
467 
468 class AndExpr : BinaryExpr
469 { }
470 
471 class XorExpr : BinaryExpr
472 { }
473 
474 class OrExpr : BinaryExpr
475 { }
476 
477 class LogicalAndExpr : BinaryExpr
478 { }
479 
480 class LogicalOrExpr : BinaryExpr
481 { }
482 
483 class CondExpr
484 {
485     Expression expr;
486     Expression left;
487     Expression right;
488 
489     override string toString()
490     {
491         import std.format : format;
492         import std.range : retro;
493         import std.algorithm.searching : findSplit;
494         import std.array : array;
495 
496         auto rname = findSplit(this.classinfo.name.retro, ".")[0].array;
497 
498         return format(
499             "CondExpr(expr = %s, left = %s, right = %s)",
500             expr,
501             left,
502             right);
503     }
504 }
505 
506 alias Expression = Algebraic!(
507     Identifier,
508     TypeIdentifier,
509     Literal,
510     StringLiteral,
511     StringifyExpr,
512     StringConcat,
513     TokenConcat,
514     IndexExpr,
515     CallExpr,
516     DotExpr,
517     ArrowExpr,
518     SubExpr,
519     UnaryExpr,
520     DefinedExpr,
521     SizeofType,
522     CastExpr,
523     MulExpr,
524     AddExpr,
525     SftExpr,
526     RelExpr,
527     EqlExpr,
528     AndExpr,
529     XorExpr,
530     OrExpr,
531     LogicalAndExpr,
532     LogicalOrExpr,
533     CondExpr);
534 
535 Expression debraced(Expression expression)
536 {
537     if (!expression.hasValue)
538         return expression;
539 
540     auto subExpr = expression.peek!SubExpr();
541 
542     return subExpr !is null ? subExpr.subexpr : expression;
543 }
544 
545 Expression braced(Expression expression)
546 {
547     if (!expression.hasValue)
548         return expression;
549 
550     if (auto subExpr = expression.peek!Identifier())
551         return expression;
552     else if (auto subExpr = expression.peek!Literal())
553         return expression;
554     else if (auto subExpr = expression.peek!SubExpr())
555         return expression;
556     else
557         return Expression(new SubExpr(expression));
558 }
559 
560 Expression parseStringConcat(ref Token[] tokens)
561 {
562     import std.array;
563 
564     auto local = tokens;
565 
566     Expression[] substrings;
567 
568     while (true)
569     {
570         string spelling;
571 
572         if (acceptStringLiteral(local, spelling))
573         {
574             substrings ~= Expression(StringLiteral(spelling));
575         }
576         else if (accept!("#")(local, TokenKind.punctuation))
577         {
578             if (!accept(local, spelling, TokenKind.identifier))
579                 return Expression.init;
580 
581             substrings ~= Expression(StringifyExpr(spelling));
582         }
583         else
584         {
585             break;
586         }
587     }
588 
589     if (substrings.length == 0)
590         return Expression.init;
591 
592     tokens = local;
593 
594     if (substrings.length == 1)
595         return substrings.front;
596 
597     return Expression(new StringConcat(substrings));
598 }
599 
600 Expression parseTokenConcat(ref Token[] tokens)
601 {
602     Expression parseSubexpr(ref Token[] tokens)
603     {
604         string spelling;
605 
606         if (acceptIdentifier(tokens, spelling))
607             return Expression(Identifier(spelling));
608 
609         if (acceptLiteral(tokens, spelling))
610             return Expression(Literal(spelling));
611 
612         return Expression.init;
613     }
614 
615     auto local = tokens;
616 
617     Expression[] subexprs;
618     auto first = parseSubexpr(local);
619 
620     if (first.hasValue)
621     {
622         if (!acceptPunctuation!("##")(local))
623             return Expression.init;
624 
625         auto expr = parseSubexpr(local);
626 
627         if (expr.hasValue)
628         {
629             subexprs ~= first;
630             subexprs ~= expr;
631 
632             tokens = local;
633 
634             while (acceptPunctuation!("##")(local))
635             {
636                 expr = parseSubexpr(local);
637 
638                 if (expr.hasValue)
639                 {
640                     subexprs ~= expr;
641                     tokens = local;
642                 }
643                 else
644                 {
645                     break;
646                 }
647             }
648 
649             return Expression(new TokenConcat(subexprs));
650         }
651     }
652 
653     return Expression.init;
654 }
655 
656 Expression parsePrimaryExpr(ref Token[] tokens, Cursor[string] table, bool defined)
657 {
658     string spelling;
659 
660     auto type = parseTypeName(tokens, table);
661 
662     if (type.isValid)
663         return Expression(TypeIdentifier(type));
664 
665     if (accept(tokens, spelling, TokenKind.identifier))
666         return Expression(Identifier(spelling));
667 
668     auto local = tokens;
669 
670     auto substrings = parseStringConcat(local);
671 
672     if (substrings.hasValue)
673     {
674         tokens = local;
675         return substrings;
676     }
677 
678     if (accept(local, spelling, TokenKind.literal))
679     {
680         tokens = local;
681         return Expression(Literal(spelling));
682     }
683 
684     if (!accept!("(")(local, TokenKind.punctuation))
685         return Expression.init;
686 
687     auto subexpr = parseExpr(local, table, defined);
688 
689     if (!subexpr.hasValue)
690         return Expression.init;
691 
692     if (!accept!(")")(local, TokenKind.punctuation))
693         return Expression.init;
694 
695     tokens = local;
696 
697     return Expression(new SubExpr(subexpr));
698 }
699 
700 Expression parseArg(ref Token[] tokens, Cursor[string] table, bool defined)
701 {
702     auto local = tokens;
703 
704     auto expression = parseSftExpr(local, table, defined);
705 
706     if (expression.hasValue)
707     {
708         tokens = local;
709         return expression;
710     }
711 
712     auto type = parseTypeName(local, table);
713 
714     if (type.isValid)
715     {
716         tokens = local;
717         expression = TypeIdentifier(type);
718     }
719 
720     return expression;
721 }
722 
723 Expression[] parseArgsList(ref Token[] tokens, Cursor[string] table, bool defined)
724 {
725     auto local = tokens;
726 
727     Expression[] exprs = [ parseArg(local, table, defined) ];
728 
729     if (!exprs[0].hasValue)
730         return null;
731 
732     while (true)
733     {
734         if (acceptPunctuation!(",")(local))
735         {
736             Expression expr = parseArg(local, table, defined);
737 
738             if (!expr.hasValue)
739                 break;
740 
741             exprs ~= expr;
742         }
743         else
744         {
745             break;
746         }
747     }
748 
749     tokens = local;
750 
751     return exprs;
752 }
753 
754 Expression parsePostfixExpr(ref Token[] tokens, Cursor[string] table, bool defined)
755 {
756     auto local = tokens;
757 
758     Expression expr = parsePrimaryExpr(local, table, defined);
759 
760     if (!expr.hasValue)
761         return expr;
762 
763     string spelling;
764 
765     while (true)
766     {
767         if (acceptPunctuation!("[")(local))
768         {
769             auto index = parseExpr(local, table, defined);
770 
771             if (!index.hasValue)
772                 break;
773 
774             if (!acceptPunctuation!("]")(local))
775                 break;
776 
777             IndexExpr subexpr = new IndexExpr;
778             subexpr.subexpr = expr;
779             subexpr.index = index;
780             expr = subexpr;
781         }
782         else if (acceptPunctuation!("(")(local))
783         {
784             if (acceptPunctuation!(")")(local))
785             {
786                 CallExpr subexpr = new CallExpr;
787                 subexpr.expr = expr;
788                 subexpr.args = [];
789                 expr = subexpr;
790             }
791             else
792             {
793                 auto args = parseArgsList(local, table, defined);
794 
795                 if (args is null)
796                     break;
797 
798                 if (!acceptPunctuation!(")")(local))
799                     break;
800 
801                 CallExpr subexpr = new CallExpr;
802                 subexpr.expr = expr;
803                 subexpr.args = args;
804                 expr = subexpr;
805             }
806         }
807         else if (acceptPunctuation!(".")(local) && acceptIdentifier(local, spelling))
808         {
809             DotExpr subexpr = new DotExpr;
810             subexpr.subexpr = expr;
811             subexpr.identifier = spelling;
812             expr = subexpr;
813         }
814         else if (acceptPunctuation!("->")(local) && acceptIdentifier(local, spelling))
815         {
816             ArrowExpr subexpr = new ArrowExpr;
817             subexpr.subexpr = expr;
818             subexpr.identifier = spelling;
819             expr = subexpr;
820         }
821         else if (acceptPunctuation!("++", "--")(local, spelling))
822         {
823             UnaryExpr subexpr = new UnaryExpr;
824             subexpr.subexpr = expr;
825             subexpr.operator = spelling;
826             subexpr.postfix = true;
827             expr = subexpr;
828         }
829         else
830         {
831             break;
832         }
833     }
834 
835     tokens = local;
836 
837     return expr;
838 }
839 
840 Expression parseSizeofType(ref Token[] tokens, Cursor[string] table)
841 {
842     auto local = tokens;
843 
844     if (acceptPunctuation!("(")(local))
845     {
846         Type type = parseTypeName(local, table);
847 
848         if (type.isValid && acceptPunctuation!(")")(local))
849         {
850             SizeofType expr = SizeofType();
851             expr.type = type;
852             tokens = local;
853             return Expression(expr);
854         }
855     }
856 
857     return Expression.init;
858 }
859 
860 Expression parseDefinedExpr(ref Token[] tokens)
861 {
862     auto local = tokens;
863 
864     if (accept!("defined")(local, TokenKind.identifier))
865     {
866         string spelling;
867 
868         if (acceptIdentifier(local, spelling))
869         {
870             auto expr = DefinedExpr();
871             expr.identifier = spelling;
872             tokens = local;
873             return Expression(expr);
874         }
875 
876         if (acceptPunctuation!("(")(local) &&
877             acceptIdentifier(local, spelling) &&
878             acceptPunctuation!(")")(local))
879         {
880             auto expr = DefinedExpr();
881             expr.identifier = spelling;
882             tokens = local;
883             return Expression(expr);
884         }
885     }
886 
887     return Expression.init;
888 }
889 
890 Expression parseUnaryExpr(ref Token[] tokens, Cursor[string] table, bool defined)
891 {
892     auto local = tokens;
893 
894     string spelling;
895 
896     if (accept!("++", "--")(local, spelling, TokenKind.punctuation))
897     {
898         Expression subexpr = parseUnaryExpr(local, table, defined);
899 
900         if (subexpr.hasValue)
901         {
902             UnaryExpr expr = new UnaryExpr;
903             expr.subexpr = subexpr;
904             expr.operator = spelling;
905             tokens = local;
906             return Expression(expr);
907         }
908     }
909 
910     if (accept!("&", "*", "+", "-", "~", "!")(local, spelling, TokenKind.punctuation))
911     {
912         Expression subexpr = parseCastExpr(local, table, defined);
913 
914         if (subexpr.hasValue)
915         {
916             UnaryExpr expr = new UnaryExpr;
917             expr.subexpr = subexpr;
918             expr.operator = spelling;
919             tokens = local;
920             return Expression(expr);
921         }
922     }
923 
924     if (accept!("sizeof")(local, spelling, TokenKind.keyword))
925     {
926         auto sizeofExpr = parseSizeofType(local, table);
927 
928         if (sizeofExpr.hasValue)
929         {
930             tokens = local;
931             return sizeofExpr;
932         }
933 
934         Expression subexpr = parseUnaryExpr(local, table, defined);
935 
936         if (subexpr.hasValue)
937         {
938             UnaryExpr expr = new UnaryExpr;
939             expr.subexpr = subexpr;
940             expr.operator = spelling;
941             tokens = local;
942             return Expression(expr);
943         }
944     }
945 
946     if (defined)
947     {
948         auto expr = parseDefinedExpr(local);
949 
950         if (expr.hasValue)
951         {
952             tokens = local;
953             return expr;
954         }
955     }
956 
957     return parsePostfixExpr(tokens, table, defined);
958 }
959 
960 Expression parseCastExpr(ref Token[] tokens, Cursor[string] table, bool defined)
961 {
962     auto local = tokens;
963 
964     if (!accept!("(")(local, TokenKind.punctuation))
965         return parseUnaryExpr(tokens, table, defined);
966 
967     Type type = parseTypeName(local, table);
968 
969     if (!type.isValid)
970         return parseUnaryExpr(tokens, table, defined);
971 
972     if (!accept!(")")(local, TokenKind.punctuation))
973         return parseUnaryExpr(tokens, table, defined);
974 
975     auto subexpr = parseCastExpr(local, table, defined);
976 
977     if (!subexpr.hasValue)
978         return parseUnaryExpr(tokens, table, defined);
979 
980     tokens = local;
981 
982     CastExpr result = new CastExpr;
983     result.type = type;
984     result.subexpr = subexpr;
985 
986     return Expression(result);
987 }
988 
989 alias parseMulExpr = parseLeftAssoc!(MulExpr, parseCastExpr, "*", "/", "%");
990 alias parseAddExpr = parseLeftAssoc!(AddExpr, parseMulExpr, "+", "-");
991 alias parseSftExpr = parseLeftAssoc!(SftExpr, parseAddExpr, "<<", ">>");
992 alias parseRelExpr = parseLeftAssoc!(RelExpr, parseSftExpr, "<", ">", "<=", ">=");
993 alias parseEqlExpr = parseLeftAssoc!(EqlExpr, parseRelExpr, "==", "!=");
994 alias parseAndExpr = parseLeftAssoc!(AndExpr, parseEqlExpr, "&");
995 alias parseXorExpr = parseLeftAssoc!(XorExpr, parseAndExpr, "^");
996 alias parseOrExpr = parseLeftAssoc!(OrExpr, parseXorExpr, "|");
997 alias parseLogicalAndExpr = parseLeftAssoc!(LogicalAndExpr, parseOrExpr, "&&");
998 alias parseLogicalOrExpr = parseLeftAssoc!(LogicalOrExpr, parseLogicalAndExpr, "||");
999 
1000 Expression parseCondExpr(ref Token[] tokens, Cursor[string] table, bool defined)
1001 {
1002     auto local = tokens;
1003 
1004     Expression expr = parseLogicalOrExpr(local, table, defined);
1005 
1006     if (!expr.hasValue)
1007         return Expression.init;
1008 
1009     tokens = local;
1010 
1011     if (acceptPunctuation!("?")(local))
1012     {
1013         Expression left = parseExpr(local, table, defined);
1014 
1015         if (left.hasValue && acceptPunctuation!(":")(local))
1016         {
1017             Expression right = parseCondExpr(local, table, defined);
1018 
1019             if (right.hasValue)
1020             {
1021                 CondExpr supexpr = new CondExpr;
1022                 supexpr.expr = expr;
1023                 supexpr.left = left;
1024                 supexpr.right = right;
1025                 expr = supexpr;
1026 
1027                 tokens = local;
1028             }
1029         }
1030     }
1031 
1032     return expr;
1033 }
1034 
1035 bool parseBasicSpecifier(ref Token[] tokens, ref string spelling, Cursor[string] table)
1036 {
1037     import std.meta : AliasSeq;
1038 
1039     alias specifiers = AliasSeq!(
1040         "void",
1041         "char",
1042         "short",
1043         "int",
1044         "long",
1045         "float",
1046         "double",
1047         "signed",
1048         "unsigned",
1049         // "__complex__", TBD
1050         // "_Complex", TBD
1051         "bool",
1052         "_Bool");
1053 
1054     return accept!(specifiers)(tokens, spelling);
1055 }
1056 
1057 bool parseRecordSpecifier(ref Token[] tokens, ref Type type, Cursor[string] table)
1058 {
1059     auto local = tokens;
1060     string spelling;
1061     string keywordType;
1062 
1063     if (accept!("struct", "union")(local, keywordType, TokenKind.keyword) &&
1064         acceptIdentifier(local, spelling))
1065     {
1066         if (auto ptr = (keywordType ~ " " ~ spelling in table))
1067         {
1068             type = ptr.type;
1069             tokens = local;
1070             return true;
1071         }
1072     }
1073 
1074     return false;
1075 }
1076 
1077 bool parseEnumSpecifier(ref Token[] tokens, ref Type type, Cursor[string] table)
1078 {
1079     auto local = tokens;
1080     string spelling;
1081 
1082     if (acceptIdentifier(local, spelling))
1083     {
1084         if (auto ptr = ("enum " ~ spelling in table))
1085         {
1086             type = ptr.type;
1087             tokens = local;
1088             return true;
1089         }
1090     }
1091 
1092     return false;
1093 }
1094 
1095 bool parseTypedefName(ref Token[] tokens, ref Type type, Cursor[string] table)
1096 {
1097     auto local = tokens;
1098     string spelling;
1099 
1100     if (acceptIdentifier(local, spelling))
1101     {
1102         if (auto ptr = (spelling in table))
1103         {
1104             type = Type.makeTypedef(spelling, ptr.type.canonical);
1105 
1106             tokens = local;
1107 
1108             return true;
1109         }
1110     }
1111 
1112     return false;
1113 }
1114 
1115 bool parseComplexSpecifier(ref Token[] tokens, ref Type type, Cursor[string] table)
1116 {
1117     return parseRecordSpecifier(tokens, type, table) ||
1118         parseEnumSpecifier(tokens, type, table) ||
1119         parseTypedefName(tokens, type, table);
1120 }
1121 
1122 bool parseTypeQualifier(ref Token[] tokens, ref string spelling)
1123 {
1124     import std.meta : AliasSeq;
1125 
1126     alias qualifiers = AliasSeq!(
1127         "const",
1128         "volatile",
1129         "_Atomic");
1130 
1131     return accept!(qualifiers)(tokens, spelling);
1132 }
1133 
1134 bool parseSpecifierQualifierList(
1135     ref Token[] tokens,
1136     ref Type type,
1137     Cursor[string] table)
1138 {
1139     auto local = tokens;
1140 
1141     Set!string specifiers;
1142     Set!string qualifiers;
1143 
1144     while (true)
1145     {
1146         string spelling;
1147 
1148         if (parseBasicSpecifier(local, spelling, table))
1149         {
1150             if (type.isValid)
1151                 return false;
1152 
1153             if (specifiers.contains(spelling))
1154             {
1155                 if (spelling == "long")
1156                 {
1157                     if (specifiers.contains("__llong"))
1158                         return false;
1159                     else
1160                         spelling = "__llong";
1161                 }
1162                 else
1163                 {
1164                     return false;
1165                 }
1166             }
1167 
1168             specifiers.add(spelling);
1169         }
1170         else if (parseComplexSpecifier(local, type, table))
1171         {
1172             if (specifiers.length != 0)
1173                 return false;
1174         }
1175         else if (parseTypeQualifier(local, spelling))
1176         {
1177             if (qualifiers.contains(spelling))
1178                 return false;
1179 
1180             qualifiers.add(spelling);
1181         }
1182         else
1183         {
1184             break;
1185         }
1186     }
1187 
1188     if (specifiers.length != 0)
1189     {
1190         if(!basicSpecifierListToType(type, specifiers))
1191             return false;
1192     }
1193 
1194     if (qualifiers.contains("const"))
1195         type.isConst = true;
1196 
1197     if (qualifiers.contains("volatile"))
1198         type.isVolatile = true;
1199 
1200     tokens = local;
1201 
1202     return true;
1203 }
1204 
1205 bool parseQualifierList(
1206     ref Token[] tokens,
1207     ref Type type)
1208 {
1209     auto local = tokens;
1210 
1211     Set!string qualifiers;
1212 
1213     while (true)
1214     {
1215         string spelling;
1216 
1217         if (parseTypeQualifier(local, spelling))
1218         {
1219             if (qualifiers.contains(spelling))
1220                 return false;
1221 
1222             qualifiers.add(spelling);
1223         }
1224         else
1225         {
1226             break;
1227         }
1228     }
1229 
1230     if (qualifiers.contains("const"))
1231         type.isConst = true;
1232 
1233     if (qualifiers.contains("volatile"))
1234         type.isVolatile = true;
1235 
1236     tokens = local;
1237 
1238     return true;
1239 }
1240 
1241 bool basicSpecifierListToType(ref Type type, Set!string specifiers)
1242 {
1243     if (specifiers.contains("void"))
1244     {
1245         if (specifiers.length != 1)
1246             return false;
1247 
1248         type = Type(CXTypeKind.void_, "void");
1249         return true;
1250     }
1251 
1252     if (specifiers.contains("bool") || specifiers.contains("_Bool"))
1253     {
1254         if (specifiers.length != 1)
1255             return false;
1256 
1257         type = Type(CXTypeKind.bool_, "bool");
1258         return true;
1259     }
1260 
1261     if (specifiers.contains("float"))
1262     {
1263         if (specifiers.length != 1)
1264             return false;
1265 
1266         type = Type(CXTypeKind.float_, "float");
1267         return true;
1268     }
1269 
1270     if (specifiers.contains("double"))
1271     {
1272         if (specifiers.contains("long"))
1273         {
1274             if (specifiers.length != 2)
1275                 return false;
1276 
1277             type = Type(CXTypeKind.longDouble, "long double");
1278 
1279             return true;
1280         }
1281 
1282         if (specifiers.length != 1)
1283             return false;
1284 
1285         type = Type(CXTypeKind.double_, "double");
1286 
1287         return true;
1288     }
1289 
1290     if ((specifiers.contains("signed") && specifiers.contains("unsigned")) ||
1291         (specifiers.contains("char") && specifiers.contains("short")) ||
1292         (specifiers.contains("char") && specifiers.contains("long")) ||
1293         (specifiers.contains("char") && specifiers.contains("__llong")) ||
1294         (specifiers.contains("short") && specifiers.contains("long")) ||
1295         (specifiers.contains("short") && specifiers.contains("__llong")))
1296         return false;
1297 
1298     if (specifiers.contains("char"))
1299     {
1300         if (specifiers.contains("signed"))
1301         {
1302             if (specifiers.length != 2)
1303                 return false;
1304 
1305             type = Type(CXTypeKind.sChar, "signed char");
1306         }
1307         else if (specifiers.contains("unsigned"))
1308         {
1309             if (specifiers.length != 2)
1310                 return false;
1311 
1312             type = Type(CXTypeKind.uChar, "unsigned char");
1313         }
1314         else
1315         {
1316             if (specifiers.length != 1)
1317                 return false;
1318 
1319             type = Type(CXTypeKind.charS, "char");
1320         }
1321 
1322         return true;
1323     }
1324 
1325     if (specifiers.contains("short"))
1326     {
1327         if (specifiers.contains("unsigned"))
1328             type = Type(CXTypeKind.uShort, "unsigned short");
1329         else
1330             type = Type(CXTypeKind.short_, "short");
1331 
1332         return true;
1333     }
1334 
1335     if (specifiers.contains("__llong"))
1336     {
1337         if (specifiers.contains("unsigned"))
1338             type = Type(CXTypeKind.uLongLong, "unsigned long long");
1339         else
1340             type = Type(CXTypeKind.longLong, "long long");
1341 
1342         return true;
1343     }
1344 
1345     if (specifiers.contains("long"))
1346     {
1347         if (specifiers.contains("unsigned"))
1348             type = Type(CXTypeKind.uLong, "unsigned long");
1349         else
1350             type = Type(CXTypeKind.long_, "long");
1351 
1352         return true;
1353     }
1354 
1355     if (specifiers.contains("int"))
1356     {
1357         if (specifiers.contains("unsigned"))
1358             type = Type(CXTypeKind.uInt, "unsigned int");
1359         else
1360             type = Type(CXTypeKind.int_, "int");
1361 
1362         return true;
1363     }
1364 
1365     if (specifiers.contains("unsigned"))
1366     {
1367         type = Type(CXTypeKind.uInt, "unsigned int");
1368         return true;
1369     }
1370 
1371     if (specifiers.contains("signed"))
1372     {
1373         type = Type(CXTypeKind.int_, "int");
1374         return true;
1375     }
1376 
1377     return false;
1378 }
1379 
1380 bool parsePointer(ref Token[] tokens, ref Type type)
1381 {
1382     if (acceptPunctuation!("*")(tokens))
1383     {
1384         type = Type.makePointer(type);
1385 
1386         if (!parsePointer(tokens, type))
1387         {
1388             if (parseQualifierList(tokens, type))
1389                 parsePointer(tokens, type);
1390         }
1391 
1392         return true;
1393     }
1394     else
1395     {
1396         return false;
1397     }
1398 }
1399 
1400 bool parseAbstractDeclarator(ref Token[] tokens, ref Type type, Cursor[string] table)
1401 {
1402     return parsePointer(tokens, type);
1403 }
1404 
1405 Type parseTypeName(ref Token[] tokens, Cursor[string] table)
1406 {
1407     auto local = tokens;
1408 
1409     Type type;
1410 
1411     if (!parseSpecifierQualifierList(local, type, table))
1412         return type;
1413 
1414     parseAbstractDeclarator(local, type, table);
1415 
1416     tokens = local;
1417 
1418     return type;
1419 }
1420 
1421 Expression parseExpr(ref Token[] tokens, Cursor[string] table, bool defined)
1422 {
1423     auto concatExpr = parseTokenConcat(tokens);
1424 
1425     if (concatExpr.hasValue)
1426         return concatExpr;
1427 
1428     auto condExpr = parseCondExpr(tokens, table, defined);
1429 
1430     if (condExpr.hasValue)
1431         return condExpr;
1432 
1433     return Expression.init;
1434 }
1435 
1436 Expression parseExpr(ref Token[] tokens, bool defined)
1437 {
1438     Cursor[string] table;
1439 
1440     return parseCondExpr(tokens, table, defined);
1441 }
1442 
1443 Expression parseEnumMember(Token[] tokens, Cursor[string] table)
1444 {
1445     string member;
1446 
1447     if (!acceptIdentifier(tokens, member))
1448         return Expression.init;
1449 
1450     if (!acceptPunctuation!("=")(tokens, member))
1451         return Expression.init;
1452 
1453     auto expression = parseExpr(tokens, table, false);
1454 
1455     if (tokens.empty)
1456         return expression;
1457     else
1458         return Expression.init;
1459 }
1460 
1461 string[] parseMacroParams(ref Token[] tokens)
1462 {
1463     auto local = tokens;
1464 
1465     string[] params;
1466 
1467     string param;
1468 
1469     if (!accept(local, param, TokenKind.identifier))
1470         return [];
1471 
1472     params ~= param;
1473 
1474     while (accept!(",")(local, TokenKind.punctuation))
1475     {
1476         if (!accept(local, param, TokenKind.identifier))
1477             return null;
1478 
1479         params ~= param;
1480     }
1481 
1482     tokens = local;
1483 
1484     return params;
1485 }
1486 
1487 class MacroDefinition
1488 {
1489     Cursor cursor;
1490     string spelling;
1491     string[] params;
1492     bool aliasOrConst;
1493     Expression expr;
1494 
1495     override string toString()
1496     {
1497         import std.format : format;
1498 
1499         return format(
1500             "MacroDefinition(spelling = %s, params = %s, aliasOrConst = %s, expr = %s)",
1501             spelling,
1502             params,
1503             aliasOrConst,
1504             expr);
1505     }
1506 
1507     void dumpAST(ref Appender!string result, size_t indent)
1508     {
1509         import std.format;
1510         import std.array : replicate;
1511         import std..string : join;
1512 
1513         result.put(" ".replicate(indent));
1514 
1515         if (aliasOrConst)
1516             formattedWrite(result, "MacroDefinition %s", spelling);
1517         else
1518             formattedWrite(result, "MacroDefinition %s(%s)", spelling, join(params, ", "));
1519     }
1520 
1521     string dumpAST()
1522     {
1523         auto result = Appender!string();
1524         dumpAST(result, 0);
1525         return result.data;
1526     }
1527 }
1528 
1529 MacroDefinition parseMacroDefinition(
1530     ref Token[] tokens,
1531     Cursor[string] table,
1532     bool defined = false)
1533 {
1534     auto local = tokens;
1535 
1536     if (!accept!("#")(local, TokenKind.punctuation))
1537         return null;
1538 
1539     if (!accept!("define")(local, TokenKind.identifier))
1540         return null;
1541 
1542     MacroDefinition result = parsePartialMacroDefinition(local, table, defined);
1543 
1544     if (result !is null)
1545         tokens = local;
1546 
1547     return result;
1548 }
1549 
1550 MacroDefinition parsePartialMacroDefinition(
1551     ref Token[] tokens,
1552     Cursor[string] table,
1553     bool defined = false)
1554 {
1555     auto local = tokens;
1556 
1557     MacroDefinition result = new MacroDefinition;
1558 
1559     if (!accept(local, result.spelling, TokenKind.identifier))
1560         return null;
1561 
1562     // Functional macros mustn't contain space before parentheses of parameter list.
1563     bool space =
1564         tokens.length > 2 &&
1565         tokens[0].extent.end.offset == tokens[1].extent.start.offset;
1566 
1567     if (space && accept!("(")(local, TokenKind.punctuation))
1568     {
1569         if (!accept!(")")(local, TokenKind.punctuation))
1570         {
1571             result.params = parseMacroParams(local);
1572 
1573             if (!accept!(")")(local, TokenKind.punctuation))
1574                 return null;
1575         }
1576     }
1577     else
1578     {
1579         result.aliasOrConst = true;
1580     }
1581 
1582     result.expr = parseExpr(local, table, defined);
1583 
1584     if (!local.empty)
1585     {
1586         return null;
1587     }
1588     else
1589     {
1590         tokens = local;
1591         return result;
1592     }
1593 }
1594 
1595 MacroDefinition[] parseMacroDefinitions(Range)(
1596     Range cursors,
1597     Cursor[string] types)
1598 {
1599     import std.algorithm;
1600     import std.array;
1601 
1602     alias predicate = (Cursor cursor) =>
1603         cursor.kind == CXCursorKind.macroDefinition;
1604 
1605     auto definitions = cursors.filter!predicate();
1606 
1607     auto macroDefinitions = appender!(MacroDefinition[]);
1608 
1609     foreach (definition; definitions) {
1610         auto tokens = definition.tokens;
1611         auto parsed = parsePartialMacroDefinition(tokens, types);
1612 
1613         if (parsed !is null && parsed.expr.hasValue)
1614         {
1615             parsed.cursor = definition;
1616             macroDefinitions.put(parsed);
1617 
1618             if (parsed.aliasOrConst)
1619             {
1620                 auto debraced = parsed.expr.debraced;
1621 
1622                 if (debraced.peek!TypeIdentifier)
1623                     types[parsed.spelling] = definition;
1624             }
1625         }
1626     }
1627 
1628     return macroDefinitions.data;
1629 }