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 }