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 parseStringConcat(ref Token[] tokens) 536 { 537 import std.array; 538 539 auto local = tokens; 540 541 Expression[] substrings; 542 543 while (true) 544 { 545 string spelling; 546 547 if (acceptStringLiteral(local, spelling)) 548 { 549 substrings ~= Expression(StringLiteral(spelling)); 550 } 551 else if (accept!("#")(local, TokenKind.punctuation)) 552 { 553 if (!accept(local, spelling, TokenKind.identifier)) 554 return Expression.init; 555 556 substrings ~= Expression(StringifyExpr(spelling)); 557 } 558 else 559 { 560 break; 561 } 562 } 563 564 if (substrings.length == 0) 565 return Expression.init; 566 567 tokens = local; 568 569 if (substrings.length == 1) 570 return substrings.front; 571 572 return Expression(new StringConcat(substrings)); 573 } 574 575 Expression parseTokenConcat(ref Token[] tokens) 576 { 577 Expression parseSubexpr(ref Token[] tokens) 578 { 579 string spelling; 580 581 if (acceptIdentifier(tokens, spelling)) 582 return Expression(Identifier(spelling)); 583 584 if (acceptLiteral(tokens, spelling)) 585 return Expression(Literal(spelling)); 586 587 return Expression.init; 588 } 589 590 auto local = tokens; 591 592 Expression[] subexprs; 593 auto first = parseSubexpr(local); 594 595 if (first.hasValue) 596 { 597 if (!acceptPunctuation!("##")(local)) 598 return Expression.init; 599 600 auto expr = parseSubexpr(local); 601 602 if (expr.hasValue) 603 { 604 subexprs ~= first; 605 subexprs ~= expr; 606 607 tokens = local; 608 609 while (acceptPunctuation!("##")(local)) 610 { 611 expr = parseSubexpr(local); 612 613 if (expr.hasValue) 614 { 615 subexprs ~= expr; 616 tokens = local; 617 } 618 else 619 { 620 break; 621 } 622 } 623 624 return Expression(new TokenConcat(subexprs)); 625 } 626 } 627 628 return Expression.init; 629 } 630 631 Expression parsePrimaryExpr(ref Token[] tokens, Cursor[string] table, bool defined) 632 { 633 string spelling; 634 635 auto type = parseTypeName(tokens, table); 636 637 if (type.isValid) 638 return Expression(TypeIdentifier(type)); 639 640 if (accept(tokens, spelling, TokenKind.identifier)) 641 return Expression(Identifier(spelling)); 642 643 auto local = tokens; 644 645 auto substrings = parseStringConcat(local); 646 647 if (substrings.hasValue) 648 { 649 tokens = local; 650 return substrings; 651 } 652 653 if (accept(local, spelling, TokenKind.literal)) 654 { 655 tokens = local; 656 return Expression(Literal(spelling)); 657 } 658 659 if (!accept!("(")(local, TokenKind.punctuation)) 660 return Expression.init; 661 662 auto subexpr = parseExpr(local, table, defined); 663 664 if (!subexpr.hasValue) 665 return Expression.init; 666 667 if (!accept!(")")(local, TokenKind.punctuation)) 668 return Expression.init; 669 670 tokens = local; 671 672 return Expression(new SubExpr(subexpr)); 673 } 674 675 Expression parseArg(ref Token[] tokens, Cursor[string] table, bool defined) 676 { 677 auto local = tokens; 678 679 auto expression = parseSftExpr(local, table, defined); 680 681 if (expression.hasValue) 682 { 683 tokens = local; 684 return expression; 685 } 686 687 auto type = parseTypeName(local, table); 688 689 if (type.isValid) 690 { 691 tokens = local; 692 expression = TypeIdentifier(type); 693 } 694 695 return expression; 696 } 697 698 Expression[] parseArgsList(ref Token[] tokens, Cursor[string] table, bool defined) 699 { 700 auto local = tokens; 701 702 Expression[] exprs = [ parseArg(local, table, defined) ]; 703 704 if (!exprs[0].hasValue) 705 return null; 706 707 while (true) 708 { 709 if (acceptPunctuation!(",")(local)) 710 { 711 Expression expr = parseArg(local, table, defined); 712 713 if (!expr.hasValue) 714 break; 715 716 exprs ~= expr; 717 } 718 else 719 { 720 break; 721 } 722 } 723 724 tokens = local; 725 726 return exprs; 727 } 728 729 Expression parsePostfixExpr(ref Token[] tokens, Cursor[string] table, bool defined) 730 { 731 auto local = tokens; 732 733 Expression expr = parsePrimaryExpr(local, table, defined); 734 735 if (!expr.hasValue) 736 return expr; 737 738 string spelling; 739 740 while (true) 741 { 742 if (acceptPunctuation!("[")(local)) 743 { 744 auto index = parseExpr(local, table, defined); 745 746 if (!index.hasValue) 747 break; 748 749 if (!acceptPunctuation!("]")(local)) 750 break; 751 752 IndexExpr subexpr = new IndexExpr; 753 subexpr.subexpr = expr; 754 subexpr.index = index; 755 expr = subexpr; 756 } 757 else if (acceptPunctuation!("(")(local)) 758 { 759 if (acceptPunctuation!(")")(local)) 760 { 761 CallExpr subexpr = new CallExpr; 762 subexpr.expr = expr; 763 subexpr.args = []; 764 expr = subexpr; 765 } 766 else 767 { 768 auto args = parseArgsList(local, table, defined); 769 770 if (args is null) 771 break; 772 773 if (!acceptPunctuation!(")")(local)) 774 break; 775 776 CallExpr subexpr = new CallExpr; 777 subexpr.expr = expr; 778 subexpr.args = args; 779 expr = subexpr; 780 } 781 } 782 else if (acceptPunctuation!(".")(local) && acceptIdentifier(local, spelling)) 783 { 784 DotExpr subexpr = new DotExpr; 785 subexpr.subexpr = expr; 786 subexpr.identifier = spelling; 787 expr = subexpr; 788 } 789 else if (acceptPunctuation!("->")(local) && acceptIdentifier(local, spelling)) 790 { 791 ArrowExpr subexpr = new ArrowExpr; 792 subexpr.subexpr = expr; 793 subexpr.identifier = spelling; 794 expr = subexpr; 795 } 796 else if (acceptPunctuation!("++", "--")(local, spelling)) 797 { 798 UnaryExpr subexpr = new UnaryExpr; 799 subexpr.subexpr = expr; 800 subexpr.operator = spelling; 801 subexpr.postfix = true; 802 expr = subexpr; 803 } 804 else 805 { 806 break; 807 } 808 } 809 810 tokens = local; 811 812 return expr; 813 } 814 815 Expression parseSizeofType(ref Token[] tokens, Cursor[string] table) 816 { 817 auto local = tokens; 818 819 if (acceptPunctuation!("(")(local)) 820 { 821 Type type = parseTypeName(local, table); 822 823 if (type.isValid && acceptPunctuation!(")")(local)) 824 { 825 SizeofType expr = SizeofType(); 826 expr.type = type; 827 tokens = local; 828 return Expression(expr); 829 } 830 } 831 832 return Expression.init; 833 } 834 835 Expression parseDefinedExpr(ref Token[] tokens) 836 { 837 auto local = tokens; 838 839 if (accept!("defined")(local, TokenKind.identifier)) 840 { 841 string spelling; 842 843 if (acceptIdentifier(local, spelling)) 844 { 845 auto expr = DefinedExpr(); 846 expr.identifier = spelling; 847 tokens = local; 848 return Expression(expr); 849 } 850 851 if (acceptPunctuation!("(")(local) && 852 acceptIdentifier(local, spelling) && 853 acceptPunctuation!(")")(local)) 854 { 855 auto expr = DefinedExpr(); 856 expr.identifier = spelling; 857 tokens = local; 858 return Expression(expr); 859 } 860 } 861 862 return Expression.init; 863 } 864 865 Expression parseUnaryExpr(ref Token[] tokens, Cursor[string] table, bool defined) 866 { 867 auto local = tokens; 868 869 string spelling; 870 871 if (accept!("++", "--")(local, spelling, TokenKind.punctuation)) 872 { 873 Expression subexpr = parseUnaryExpr(local, table, defined); 874 875 if (subexpr.hasValue) 876 { 877 UnaryExpr expr = new UnaryExpr; 878 expr.subexpr = subexpr; 879 expr.operator = spelling; 880 tokens = local; 881 return Expression(expr); 882 } 883 } 884 885 if (accept!("&", "*", "+", "-", "~", "!")(local, spelling, TokenKind.punctuation)) 886 { 887 Expression subexpr = parseCastExpr(local, table, defined); 888 889 if (subexpr.hasValue) 890 { 891 UnaryExpr expr = new UnaryExpr; 892 expr.subexpr = subexpr; 893 expr.operator = spelling; 894 tokens = local; 895 return Expression(expr); 896 } 897 } 898 899 if (accept!("sizeof")(local, spelling, TokenKind.keyword)) 900 { 901 auto sizeofExpr = parseSizeofType(local, table); 902 903 if (sizeofExpr.hasValue) 904 { 905 tokens = local; 906 return sizeofExpr; 907 } 908 909 Expression subexpr = parseUnaryExpr(local, table, defined); 910 911 if (subexpr.hasValue) 912 { 913 UnaryExpr expr = new UnaryExpr; 914 expr.subexpr = subexpr; 915 expr.operator = spelling; 916 tokens = local; 917 return Expression(expr); 918 } 919 } 920 921 if (defined) 922 { 923 auto expr = parseDefinedExpr(local); 924 925 if (expr.hasValue) 926 { 927 tokens = local; 928 return expr; 929 } 930 } 931 932 return parsePostfixExpr(tokens, table, defined); 933 } 934 935 Expression parseCastExpr(ref Token[] tokens, Cursor[string] table, bool defined) 936 { 937 auto local = tokens; 938 939 if (!accept!("(")(local, TokenKind.punctuation)) 940 return parseUnaryExpr(tokens, table, defined); 941 942 Type type = parseTypeName(local, table); 943 944 if (!type.isValid) 945 return parseUnaryExpr(tokens, table, defined); 946 947 if (!accept!(")")(local, TokenKind.punctuation)) 948 return parseUnaryExpr(tokens, table, defined); 949 950 auto subexpr = parseCastExpr(local, table, defined); 951 952 if (!subexpr.hasValue) 953 return parseUnaryExpr(tokens, table, defined); 954 955 tokens = local; 956 957 CastExpr result = new CastExpr; 958 result.type = type; 959 result.subexpr = subexpr; 960 961 return Expression(result); 962 } 963 964 alias parseMulExpr = parseLeftAssoc!(MulExpr, parseCastExpr, "*", "/", "%"); 965 alias parseAddExpr = parseLeftAssoc!(AddExpr, parseMulExpr, "+", "-"); 966 alias parseSftExpr = parseLeftAssoc!(SftExpr, parseAddExpr, "<<", ">>"); 967 alias parseRelExpr = parseLeftAssoc!(RelExpr, parseSftExpr, "<", ">", "<=", ">="); 968 alias parseEqlExpr = parseLeftAssoc!(EqlExpr, parseRelExpr, "==", "!="); 969 alias parseAndExpr = parseLeftAssoc!(AndExpr, parseEqlExpr, "&"); 970 alias parseXorExpr = parseLeftAssoc!(XorExpr, parseAndExpr, "^"); 971 alias parseOrExpr = parseLeftAssoc!(OrExpr, parseXorExpr, "|"); 972 alias parseLogicalAndExpr = parseLeftAssoc!(LogicalAndExpr, parseOrExpr, "&&"); 973 alias parseLogicalOrExpr = parseLeftAssoc!(LogicalOrExpr, parseLogicalAndExpr, "||"); 974 975 Expression parseCondExpr(ref Token[] tokens, Cursor[string] table, bool defined) 976 { 977 auto local = tokens; 978 979 Expression expr = parseLogicalOrExpr(local, table, defined); 980 981 if (!expr.hasValue) 982 return Expression.init; 983 984 tokens = local; 985 986 if (acceptPunctuation!("?")(local)) 987 { 988 Expression left = parseExpr(local, table, defined); 989 990 if (left.hasValue && acceptPunctuation!(":")(local)) 991 { 992 Expression right = parseCondExpr(local, table, defined); 993 994 if (right.hasValue) 995 { 996 CondExpr supexpr = new CondExpr; 997 supexpr.expr = expr; 998 supexpr.left = left; 999 supexpr.right = right; 1000 expr = supexpr; 1001 1002 tokens = local; 1003 } 1004 } 1005 } 1006 1007 return expr; 1008 } 1009 1010 bool parseBasicSpecifier(ref Token[] tokens, ref string spelling, Cursor[string] table) 1011 { 1012 import std.meta : AliasSeq; 1013 1014 alias specifiers = AliasSeq!( 1015 "void", 1016 "char", 1017 "short", 1018 "int", 1019 "long", 1020 "float", 1021 "double", 1022 "signed", 1023 "unsigned", 1024 // "__complex__", TBD 1025 // "_Complex", TBD 1026 "bool", 1027 "_Bool"); 1028 1029 return accept!(specifiers)(tokens, spelling); 1030 } 1031 1032 bool parseRecordSpecifier(ref Token[] tokens, ref Type type, Cursor[string] table) 1033 { 1034 auto local = tokens; 1035 string spelling; 1036 string keywordType; 1037 1038 if (accept!("struct", "union")(local, keywordType, TokenKind.keyword) && 1039 acceptIdentifier(local, spelling)) 1040 { 1041 if (auto ptr = (keywordType ~ " " ~ spelling in table)) 1042 { 1043 type = ptr.type; 1044 tokens = local; 1045 return true; 1046 } 1047 } 1048 1049 return false; 1050 } 1051 1052 bool parseEnumSpecifier(ref Token[] tokens, ref Type type, Cursor[string] table) 1053 { 1054 auto local = tokens; 1055 string spelling; 1056 1057 if (acceptIdentifier(local, spelling)) 1058 { 1059 if (auto ptr = ("enum " ~ spelling in table)) 1060 { 1061 type = ptr.type; 1062 tokens = local; 1063 return true; 1064 } 1065 } 1066 1067 return false; 1068 } 1069 1070 bool parseTypedefName(ref Token[] tokens, ref Type type, Cursor[string] table) 1071 { 1072 auto local = tokens; 1073 string spelling; 1074 1075 if (acceptIdentifier(local, spelling)) 1076 { 1077 if (auto ptr = (spelling in table)) 1078 { 1079 type = Type.makeTypedef(spelling, ptr.type.canonical); 1080 1081 tokens = local; 1082 1083 return true; 1084 } 1085 } 1086 1087 return false; 1088 } 1089 1090 bool parseComplexSpecifier(ref Token[] tokens, ref Type type, Cursor[string] table) 1091 { 1092 return parseRecordSpecifier(tokens, type, table) || 1093 parseEnumSpecifier(tokens, type, table) || 1094 parseTypedefName(tokens, type, table); 1095 } 1096 1097 bool parseTypeQualifier(ref Token[] tokens, ref string spelling) 1098 { 1099 import std.meta : AliasSeq; 1100 1101 alias qualifiers = AliasSeq!( 1102 "const", 1103 "volatile", 1104 "_Atomic"); 1105 1106 return accept!(qualifiers)(tokens, spelling); 1107 } 1108 1109 bool parseSpecifierQualifierList( 1110 ref Token[] tokens, 1111 ref Type type, 1112 Cursor[string] table) 1113 { 1114 auto local = tokens; 1115 1116 Set!string specifiers; 1117 Set!string qualifiers; 1118 1119 while (true) 1120 { 1121 string spelling; 1122 1123 if (parseBasicSpecifier(local, spelling, table)) 1124 { 1125 if (type.isValid) 1126 return false; 1127 1128 if (specifiers.contains(spelling)) 1129 { 1130 if (spelling == "long") 1131 { 1132 if (specifiers.contains("__llong")) 1133 return false; 1134 else 1135 spelling = "__llong"; 1136 } 1137 else 1138 { 1139 return false; 1140 } 1141 } 1142 1143 specifiers.add(spelling); 1144 } 1145 else if (parseComplexSpecifier(local, type, table)) 1146 { 1147 if (specifiers.length != 0) 1148 return false; 1149 } 1150 else if (parseTypeQualifier(local, spelling)) 1151 { 1152 if (qualifiers.contains(spelling)) 1153 return false; 1154 1155 qualifiers.add(spelling); 1156 } 1157 else 1158 { 1159 break; 1160 } 1161 } 1162 1163 if (specifiers.length != 0) 1164 { 1165 if(!basicSpecifierListToType(type, specifiers)) 1166 return false; 1167 } 1168 1169 if (qualifiers.contains("const")) 1170 type.isConst = true; 1171 1172 if (qualifiers.contains("volatile")) 1173 type.isVolatile = true; 1174 1175 tokens = local; 1176 1177 return true; 1178 } 1179 1180 bool parseQualifierList( 1181 ref Token[] tokens, 1182 ref Type type) 1183 { 1184 auto local = tokens; 1185 1186 Set!string qualifiers; 1187 1188 while (true) 1189 { 1190 string spelling; 1191 1192 if (parseTypeQualifier(local, spelling)) 1193 { 1194 if (qualifiers.contains(spelling)) 1195 return false; 1196 1197 qualifiers.add(spelling); 1198 } 1199 else 1200 { 1201 break; 1202 } 1203 } 1204 1205 if (qualifiers.contains("const")) 1206 type.isConst = true; 1207 1208 if (qualifiers.contains("volatile")) 1209 type.isVolatile = true; 1210 1211 tokens = local; 1212 1213 return true; 1214 } 1215 1216 bool basicSpecifierListToType(ref Type type, Set!string specifiers) 1217 { 1218 if (specifiers.contains("void")) 1219 { 1220 if (specifiers.length != 1) 1221 return false; 1222 1223 type = Type(CXTypeKind.void_, "void"); 1224 return true; 1225 } 1226 1227 if (specifiers.contains("bool") || specifiers.contains("_Bool")) 1228 { 1229 if (specifiers.length != 1) 1230 return false; 1231 1232 type = Type(CXTypeKind.bool_, "bool"); 1233 return true; 1234 } 1235 1236 if (specifiers.contains("float")) 1237 { 1238 if (specifiers.length != 1) 1239 return false; 1240 1241 type = Type(CXTypeKind.float_, "float"); 1242 return true; 1243 } 1244 1245 if (specifiers.contains("double")) 1246 { 1247 if (specifiers.contains("long")) 1248 { 1249 if (specifiers.length != 2) 1250 return false; 1251 1252 type = Type(CXTypeKind.longDouble, "long double"); 1253 1254 return true; 1255 } 1256 1257 if (specifiers.length != 1) 1258 return false; 1259 1260 type = Type(CXTypeKind.double_, "double"); 1261 1262 return true; 1263 } 1264 1265 if ((specifiers.contains("signed") && specifiers.contains("unsigned")) || 1266 (specifiers.contains("char") && specifiers.contains("short")) || 1267 (specifiers.contains("char") && specifiers.contains("long")) || 1268 (specifiers.contains("char") && specifiers.contains("__llong")) || 1269 (specifiers.contains("short") && specifiers.contains("long")) || 1270 (specifiers.contains("short") && specifiers.contains("__llong"))) 1271 return false; 1272 1273 if (specifiers.contains("char")) 1274 { 1275 if (specifiers.contains("signed")) 1276 { 1277 if (specifiers.length != 2) 1278 return false; 1279 1280 type = Type(CXTypeKind.sChar, "signed char"); 1281 } 1282 else if (specifiers.contains("unsigned")) 1283 { 1284 if (specifiers.length != 2) 1285 return false; 1286 1287 type = Type(CXTypeKind.uChar, "unsigned char"); 1288 } 1289 else 1290 { 1291 if (specifiers.length != 1) 1292 return false; 1293 1294 type = Type(CXTypeKind.charS, "char"); 1295 } 1296 1297 return true; 1298 } 1299 1300 if (specifiers.contains("short")) 1301 { 1302 if (specifiers.contains("unsigned")) 1303 type = Type(CXTypeKind.uShort, "unsigned short"); 1304 else 1305 type = Type(CXTypeKind.short_, "short"); 1306 1307 return true; 1308 } 1309 1310 if (specifiers.contains("__llong")) 1311 { 1312 if (specifiers.contains("unsigned")) 1313 type = Type(CXTypeKind.uLongLong, "unsigned long long"); 1314 else 1315 type = Type(CXTypeKind.longLong, "long long"); 1316 1317 return true; 1318 } 1319 1320 if (specifiers.contains("long")) 1321 { 1322 if (specifiers.contains("unsigned")) 1323 type = Type(CXTypeKind.uLong, "unsigned long"); 1324 else 1325 type = Type(CXTypeKind.long_, "long"); 1326 1327 return true; 1328 } 1329 1330 if (specifiers.contains("int")) 1331 { 1332 if (specifiers.contains("unsigned")) 1333 type = Type(CXTypeKind.uInt, "unsigned int"); 1334 else 1335 type = Type(CXTypeKind.int_, "int"); 1336 1337 return true; 1338 } 1339 1340 if (specifiers.contains("unsigned")) 1341 { 1342 type = Type(CXTypeKind.uInt, "unsigned int"); 1343 return true; 1344 } 1345 1346 if (specifiers.contains("signed")) 1347 { 1348 type = Type(CXTypeKind.int_, "int"); 1349 return true; 1350 } 1351 1352 return false; 1353 } 1354 1355 bool parsePointer(ref Token[] tokens, ref Type type) 1356 { 1357 if (acceptPunctuation!("*")(tokens)) 1358 { 1359 type = Type.makePointer(type); 1360 1361 if (!parsePointer(tokens, type)) 1362 { 1363 if (parseQualifierList(tokens, type)) 1364 parsePointer(tokens, type); 1365 } 1366 1367 return true; 1368 } 1369 else 1370 { 1371 return false; 1372 } 1373 } 1374 1375 bool parseAbstractDeclarator(ref Token[] tokens, ref Type type, Cursor[string] table) 1376 { 1377 return parsePointer(tokens, type); 1378 } 1379 1380 Type parseTypeName(ref Token[] tokens, Cursor[string] table) 1381 { 1382 auto local = tokens; 1383 1384 Type type; 1385 1386 if (!parseSpecifierQualifierList(local, type, table)) 1387 return type; 1388 1389 parseAbstractDeclarator(local, type, table); 1390 1391 tokens = local; 1392 1393 return type; 1394 } 1395 1396 Expression parseExpr(ref Token[] tokens, Cursor[string] table, bool defined) 1397 { 1398 auto concatExpr = parseTokenConcat(tokens); 1399 1400 if (concatExpr.hasValue) 1401 return concatExpr; 1402 1403 auto condExpr = parseCondExpr(tokens, table, defined); 1404 1405 if (condExpr.hasValue) 1406 return condExpr; 1407 1408 return Expression.init; 1409 } 1410 1411 Expression parseExpr(ref Token[] tokens, bool defined) 1412 { 1413 Cursor[string] table; 1414 1415 return parseCondExpr(tokens, table, defined); 1416 } 1417 1418 Expression parseEnumMember(Token[] tokens, Cursor[string] table) 1419 { 1420 string member; 1421 1422 if (!acceptIdentifier(tokens, member)) 1423 return Expression.init; 1424 1425 if (!acceptPunctuation!("=")(tokens, member)) 1426 return Expression.init; 1427 1428 auto expression = parseExpr(tokens, table, false); 1429 1430 if (tokens.empty) 1431 return expression; 1432 else 1433 return Expression.init; 1434 } 1435 1436 string[] parseMacroParams(ref Token[] tokens) 1437 { 1438 auto local = tokens; 1439 1440 string[] params; 1441 1442 string param; 1443 1444 if (!accept(local, param, TokenKind.identifier)) 1445 return []; 1446 1447 params ~= param; 1448 1449 while (accept!(",")(local, TokenKind.punctuation)) 1450 { 1451 if (!accept(local, param, TokenKind.identifier)) 1452 return null; 1453 1454 params ~= param; 1455 } 1456 1457 tokens = local; 1458 1459 return params; 1460 } 1461 1462 class MacroDefinition 1463 { 1464 Cursor cursor; 1465 string spelling; 1466 string[] params; 1467 bool constant; 1468 Expression expr; 1469 1470 override string toString() 1471 { 1472 import std.format : format; 1473 1474 return format( 1475 "MacroDefinition(spelling = %s, params = %s, constant = %s, expr = %s)", 1476 spelling, 1477 params, 1478 constant, 1479 expr); 1480 } 1481 1482 void dumpAST(ref Appender!string result, size_t indent) 1483 { 1484 import std.format; 1485 import std.array : replicate; 1486 import std..string : join; 1487 1488 result.put(" ".replicate(indent)); 1489 1490 if (constant) 1491 formattedWrite(result, "MacroDefinition %s", spelling); 1492 else 1493 formattedWrite(result, "MacroDefinition %s(%s)", spelling, join(params, ", ")); 1494 } 1495 1496 string dumpAST() 1497 { 1498 auto result = Appender!string(); 1499 dumpAST(result, 0); 1500 return result.data; 1501 } 1502 } 1503 1504 MacroDefinition parseMacroDefinition( 1505 ref Token[] tokens, 1506 Cursor[string] table, 1507 bool defined = false) 1508 { 1509 auto local = tokens; 1510 1511 if (!accept!("#")(local, TokenKind.punctuation)) 1512 return null; 1513 1514 if (!accept!("define")(local, TokenKind.identifier)) 1515 return null; 1516 1517 MacroDefinition result = parsePartialMacroDefinition(local, table, defined); 1518 1519 if (result !is null) 1520 tokens = local; 1521 1522 return result; 1523 } 1524 1525 MacroDefinition parsePartialMacroDefinition( 1526 ref Token[] tokens, 1527 Cursor[string] table, 1528 bool defined = false) 1529 { 1530 auto local = tokens; 1531 1532 MacroDefinition result = new MacroDefinition; 1533 1534 if (!accept(local, result.spelling, TokenKind.identifier)) 1535 return null; 1536 1537 // Functional macros mustn't contain space before parentheses of parameter list. 1538 bool space = 1539 tokens.length > 2 && 1540 tokens[0].extent.end.offset == tokens[1].extent.start.offset; 1541 1542 if (space && accept!("(")(local, TokenKind.punctuation)) 1543 { 1544 if (!accept!(")")(local, TokenKind.punctuation)) 1545 { 1546 result.params = parseMacroParams(local); 1547 1548 if (!accept!(")")(local, TokenKind.punctuation)) 1549 return null; 1550 } 1551 } 1552 else 1553 { 1554 result.constant = true; 1555 } 1556 1557 result.expr = parseExpr(local, table, defined); 1558 1559 if (!local.empty) 1560 { 1561 return null; 1562 } 1563 else 1564 { 1565 tokens = local; 1566 return result; 1567 } 1568 } 1569 1570 MacroDefinition[] parseMacroDefinitions(Range)( 1571 Range cursors, 1572 Cursor[string] types) 1573 { 1574 import std.algorithm; 1575 import std.array; 1576 1577 alias predicate = (Cursor cursor) => 1578 cursor.kind == CXCursorKind.macroDefinition; 1579 auto definitions = cursors.filter!predicate(); 1580 1581 auto macroDefinitions = appender!(MacroDefinition[]); 1582 1583 foreach (definition; definitions) { 1584 auto tokens = definition.tokens; 1585 auto parsed = parsePartialMacroDefinition(tokens, types); 1586 1587 if (parsed !is null && parsed.expr.hasValue) 1588 { 1589 parsed.cursor = definition; 1590 macroDefinitions.put(parsed); 1591 } 1592 } 1593 1594 return macroDefinitions.data; 1595 }