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 }