1 module d.parser.conditional; 2 3 import d.ast.conditional; 4 import d.ast.declaration; 5 import d.ast.statement; 6 7 import d.parser.base; 8 import d.parser.declaration; 9 import d.parser.expression; 10 import d.parser.statement; 11 12 /** 13 * Parse Version Declaration 14 */ 15 auto parseVersion(ItemType)(ref TokenRange trange) if(is(ItemType == Statement) || is(ItemType == Declaration)) { 16 return trange.parseconditionalBlock!(true, ItemType)(); 17 } 18 19 /** 20 * Parse Debug Declaration 21 */ 22 auto parseDebug(ItemType)(ref TokenRange trange) if(is(ItemType == Statement) || is(ItemType == Declaration)) { 23 return trange.parseconditionalBlock!(false, ItemType)(); 24 } 25 26 private ItemType parseconditionalBlock(bool isVersion, ItemType)(ref TokenRange trange) { 27 static if (isVersion) { 28 alias TokenType.Version conditionalTokenType; 29 alias Version!ItemType ConditionalType; 30 alias VersionDefinition!ItemType DefinitionType; 31 } else { 32 alias TokenType.Debug conditionalTokenType; 33 alias Debug!ItemType ConditionalType; 34 alias DebugDefinition!ItemType DefinitionType; 35 } 36 37 Location location = trange.front.location; 38 trange.match(conditionalTokenType); 39 40 // TODO: refactor. 41 switch(trange.front.type) with(TokenType) { 42 case OpenParen: 43 trange.popFront(); 44 45 import source.name; 46 Name versionId; 47 switch(trange.front.type) { 48 case Identifier : 49 versionId = trange.front.name; 50 trange.match(Identifier); 51 52 break; 53 54 case Unittest: 55 static if (isVersion) { 56 trange.popFront(); 57 versionId = BuiltinName!"unittest"; 58 break; 59 } else { 60 // unittest isn't a special token for debug. 61 goto default; 62 } 63 64 default: 65 assert(0); 66 } 67 68 trange.match(TokenType.CloseParen); 69 70 ItemType[] items = trange.parseItems!ItemType(); 71 ItemType[] elseItems; 72 73 if (trange.front.type == Else) { 74 trange.popFront(); 75 76 elseItems = trange.parseItems!ItemType(); 77 } 78 79 return new ConditionalType(location, versionId, items, elseItems); 80 81 case Equal: 82 trange.popFront(); 83 auto versionId = trange.front.name; 84 trange.match(Identifier); 85 trange.match(Semicolon); 86 87 return new DefinitionType(location, versionId); 88 89 default: 90 // TODO: error. 91 assert(0); 92 } 93 } 94 95 /** 96 * Parse static if. 97 */ 98 ItemType parseStaticIf(ItemType)(ref TokenRange trange) if(is(ItemType == Statement) || is(ItemType == Declaration)) { 99 auto location = trange.front.location; 100 101 trange.match(TokenType.Static); 102 trange.match(TokenType.If); 103 trange.match(TokenType.OpenParen); 104 105 auto condition = trange.parseExpression(); 106 107 trange.match(TokenType.CloseParen); 108 109 ItemType[] items = trange.parseItems!ItemType(); 110 111 if (trange.front.type != TokenType.Else) { 112 return new StaticIf!ItemType(location, condition, items, []); 113 } 114 115 trange.popFront(); 116 117 ItemType[] elseItems = trange.parseItems!ItemType(); 118 119 return new StaticIf!ItemType(location, condition, items, elseItems); 120 } 121 122 /** 123 * Parse the content of the conditionnal depending on if it is statement or declaration that are expected. 124 */ 125 private auto parseItems(ItemType)(ref TokenRange trange) { 126 switch(trange.front.type) with(TokenType) { 127 static if(is(ItemType == Statement)) { 128 case OpenBrace : 129 trange.popFront(); 130 131 ItemType[] items; 132 while(trange.front.type != TokenType.CloseBrace) { 133 items ~= trange.parseStatement(); 134 } 135 136 trange.popFront(); 137 return items; 138 139 default : 140 return [trange.parseStatement()]; 141 } else { 142 case OpenBrace : 143 return trange.parseAggregate(); 144 145 case Colon : 146 trange.popFront(); 147 return trange.parseAggregate!false(); 148 149 default : 150 return [trange.parseDeclaration()]; 151 } 152 } 153 } 154 155 /** 156 * Parse mixins. 157 */ 158 auto parseMixin(ItemType)(ref TokenRange trange) if(is(Mixin!ItemType)) { 159 auto location = trange.front.location; 160 161 trange.match(TokenType.Mixin); 162 trange.match(TokenType.OpenParen); 163 164 auto expression = trange.parseAssignExpression(); 165 166 trange.match(TokenType.CloseParen); 167 168 import d.ast.expression : AstExpression; 169 static if (!is(ItemType == AstExpression)) { 170 trange.match(TokenType.Semicolon); 171 } 172 173 location.spanTo(trange.previous); 174 return new Mixin!ItemType(location, expression); 175 } 176 177 /** 178 * Parse static assert. 179 */ 180 ItemType parseStaticAssert(ItemType)(ref TokenRange trange) if(is(ItemType == Statement) || is(ItemType == Declaration)) { 181 auto location = trange.front.location; 182 183 trange.match(TokenType.Static); 184 trange.match(TokenType.Assert); 185 trange.match(TokenType.OpenParen); 186 187 auto condition = trange.parseAssignExpression(); 188 189 import d.ast.expression; 190 AstExpression message; 191 if (trange.front.type == TokenType.Comma) { 192 trange.popFront(); 193 message = trange.parseAssignExpression(); 194 195 if (trange.front.type == TokenType.Comma) { 196 trange.popFront(); 197 } 198 } 199 200 trange.match(TokenType.CloseParen); 201 location.spanTo(trange.front.location); 202 203 trange.match(TokenType.Semicolon); 204 return new StaticAssert!ItemType(location, condition, message); 205 }