1 module d.parser.adt;
2 
3 import d.parser.base;
4 import d.parser.declaration;
5 import d.parser.dtemplate;
6 import d.parser.expression;
7 import d.parser.identifier;
8 import d.parser.type;
9 
10 import d.ast.declaration;
11 import d.ast.expression;
12 import d.ast.identifier;
13 import d.ast.type;
14 
15 /**
16  * Parse class
17  */
18 auto parseClass(ref TokenRange trange, StorageClass stc) {
19 	return trange.parsePolymorphic!true(stc);
20 }
21 
22 /**
23  * Parse interface
24  */
25 auto parseInterface(ref TokenRange trange, StorageClass stc) {
26 	return trange.parsePolymorphic!false(stc);
27 }
28 
29 private Declaration parsePolymorphic(bool isClass = true)(ref TokenRange trange, StorageClass stc) {
30 	Location location = trange.front.location;
31 	
32 	static if (isClass) {
33 		trange.match(TokenType.Class);
34 		alias DeclarationType = ClassDeclaration;
35 	} else {
36 		trange.match(TokenType.Interface);
37 		alias DeclarationType = InterfaceDeclaration;
38 	}
39 	
40 	AstTemplateParameter[] parameters;
41 	if (trange.front.type == TokenType.OpenParen) {
42 		parameters = trange.parseTemplateParameters();
43 	}
44 	
45 	auto name = trange.front.name;
46 	trange.match(TokenType.Identifier);
47 	
48 	Identifier[] bases;
49 	if (trange.front.type == TokenType.Colon) {
50 		do {
51 			trange.popFront();
52 			bases ~= trange.parseIdentifier();
53 		} while(trange.front.type == TokenType.Comma);
54 	}
55 	
56 	if (parameters.ptr) {
57 		if (trange.front.type == TokenType.If) {
58 			trange.parseConstraint();
59 		}
60 	}
61 	
62 	auto members = trange.parseAggregate();
63 	
64 	location.spanTo(trange.previous);
65 	
66 	auto adt = new DeclarationType(location, stc, name, bases, members);
67 	
68 	if (parameters.ptr) {
69 		return new TemplateDeclaration(location, stc, name, parameters, [adt]);
70 	} else {
71 		return adt;
72 	}
73 }
74 
75 /**
76  * Parse struct
77  */
78 auto parseStruct(ref TokenRange trange, StorageClass stc) {
79 	return trange.parseMonomorphic!true(stc);
80 }
81 
82 /**
83  * Parse union
84  */
85 auto parseUnion(ref TokenRange trange, StorageClass stc) {
86 	return trange.parseMonomorphic!false(stc);
87 }
88 
89 private Declaration parseMonomorphic(bool isStruct = true)(ref TokenRange trange, StorageClass stc) {
90 	Location location = trange.front.location;
91 	
92 	static if (isStruct) {
93 		trange.match(TokenType.Struct);
94 		alias DeclarationType = StructDeclaration;
95 	} else {
96 		trange.match(TokenType.Union);
97 		alias DeclarationType = UnionDeclaration;
98 	}
99 	
100 	import source.name;
101 	Name name;
102 	AstTemplateParameter[] parameters;
103 	
104 	if (trange.front.type == TokenType.Identifier) {
105 		name = trange.front.name;
106 		trange.popFront();
107 		
108 		switch(trange.front.type) {
109 			// Handle opaque declarations.
110 			case TokenType.Semicolon :
111 				location.spanTo(trange.front.location);
112 				
113 				trange.popFront();
114 				
115 				assert(0, "Opaque declaration aren't supported.");
116 			
117 			// Template structs
118 			case TokenType.OpenParen :
119 				parameters = trange.parseTemplateParameters();
120 				
121 				if(trange.front.type == TokenType.If) {
122 					trange.parseConstraint();
123 				}
124 				
125 				break;
126 			
127 			default :
128 				break;
129 		}
130 	}
131 	
132 	auto members = trange.parseAggregate();
133 	
134 	location.spanTo(trange.previous);
135 	
136 	auto adt = new DeclarationType(location, stc, name, members);
137 	
138 	if (parameters.ptr) {
139 		return new TemplateDeclaration(location, stc, name, parameters, [adt]);
140 	} else {
141 		return adt;
142 	}
143 }
144 
145 /**
146  * Parse enums
147  */
148 Declaration parseEnum(ref TokenRange trange, StorageClass stc) in {
149 	assert(stc.isEnum == true);
150 } do {
151 	Location location = trange.front.location;
152 	trange.match(TokenType.Enum);
153 	
154 	import source.name;
155 	Name name;
156 	AstType type = AstType.getAuto();
157 	
158 	switch(trange.front.type) with(TokenType) {
159 		case Identifier :
160 			name = trange.front.name;
161 			trange.popFront();
162 			
163 			// Ensure we are not in case of manifest constant.
164 			assert(trange.front.type != Equal, "Manifest constant must be parsed as auto declaration and not as enums.");
165 			
166 			// If we have a colon, we go to the apropriate case.
167 			if (trange.front.type == Colon) {
168 				goto case Colon;
169 			}
170 			
171 			// If not, then it is time to parse the enum content.
172 			goto case OpenBrace;
173 		
174 		case Colon :
175 			trange.popFront();
176 			type = trange.parseType();
177 			
178 			break;
179 		
180 		case OpenBrace :
181 			break;
182 		
183 		default :
184 			// TODO: error.
185 			trange.match(Begin);
186 	}
187 	
188 	trange.match(TokenType.OpenBrace);
189 	VariableDeclaration[] enumEntries;
190 	
191 	while(trange.front.type != TokenType.CloseBrace) {
192 		auto entryName = trange.front.name;
193 		auto entryLocation = trange.front.location;
194 		
195 		trange.match(TokenType.Identifier);
196 		
197 		AstExpression entryValue;
198 		if (trange.front.type == TokenType.Equal) {
199 			trange.popFront();
200 			
201 			entryValue = trange.parseAssignExpression();
202 			
203 			// FIXME: don't work for whatever reason.
204 			// entryLocation.spanTo(entryValue.location);
205 		}
206 		
207 		enumEntries ~= new VariableDeclaration(entryLocation, stc, type, entryName, entryValue);
208 		
209 		// If it is not a comma, then we abort the loop.
210 		if (trange.front.type != TokenType.Comma) break;
211 		
212 		trange.popFront();
213 	}
214 	
215 	location.spanTo(trange.front.location);
216 	trange.match(TokenType.CloseBrace);
217 	
218 	return new EnumDeclaration(location, stc, name, type, enumEntries);
219 }