1 // Copyright Brian Schott 2015. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 module dfmt.ast_info; 7 8 import dparse.lexer; 9 import dparse.ast; 10 11 enum BraceIndentInfoFlags 12 { 13 tempIndent = 1 << 0, 14 } 15 16 struct BraceIndentInfo 17 { 18 size_t startLocation; 19 size_t endLocation; 20 21 uint flags; 22 23 uint beginIndentLevel; 24 } 25 26 /// AST information that is needed by the formatter. 27 struct ASTInformation 28 { 29 /// Sorts the arrays so that binary search will work on them 30 void cleanup() 31 { 32 import std.algorithm : sort; 33 34 sort(doubleNewlineLocations); 35 sort(spaceAfterLocations); 36 sort(unaryLocations); 37 sort(attributeDeclarationLines); 38 sort(caseEndLocations); 39 sort(structInitStartLocations); 40 sort(structInitEndLocations); 41 sort(funLitStartLocations); 42 sort(funLitEndLocations); 43 sort(conditionalWithElseLocations); 44 sort(conditionalStatementLocations); 45 sort(arrayStartLocations); 46 sort(contractLocations); 47 sort(constraintLocations); 48 sort(constructorDestructorLocations); 49 sort(staticConstructorDestructorLocations); 50 sort(sharedStaticConstructorDestructorLocations); 51 52 sort!((a,b) => a.endLocation < b.endLocation) 53 (indentInfoSortedByEndLocation); 54 } 55 56 /// Locations of end braces for struct bodies 57 size_t[] doubleNewlineLocations; 58 59 /// Locations of tokens where a space is needed (such as the '*' in a type) 60 size_t[] spaceAfterLocations; 61 62 /// Locations of unary operators 63 size_t[] unaryLocations; 64 65 /// Lines containing attribute declarations 66 size_t[] attributeDeclarationLines; 67 68 /// Case statement colon locations 69 size_t[] caseEndLocations; 70 71 /// Opening braces of struct initializers 72 size_t[] structInitStartLocations; 73 74 /// Closing braces of struct initializers 75 size_t[] structInitEndLocations; 76 77 /// Opening braces of function literals 78 size_t[] funLitStartLocations; 79 80 /// Closing braces of function literals 81 size_t[] funLitEndLocations; 82 83 /// Conditional statements that have matching "else" statements 84 size_t[] conditionalWithElseLocations; 85 86 /// Conditional statement locations 87 size_t[] conditionalStatementLocations; 88 89 /// Locations of start locations of array initializers 90 size_t[] arrayStartLocations; 91 92 /// Locations of "in" and "out" tokens that begin contracts 93 size_t[] contractLocations; 94 95 /// Locations of template constraint "if" tokens 96 size_t[] constraintLocations; 97 98 /// Locations of constructor/destructor "shared" tokens ? 99 size_t[] sharedStaticConstructorDestructorLocations; 100 101 /// Locations of constructor/destructor "static" tokens ? 102 size_t[] staticConstructorDestructorLocations; 103 104 /// Locations of constructor/destructor "this" tokens ? 105 size_t[] constructorDestructorLocations; 106 107 BraceIndentInfo[] indentInfoSortedByEndLocation; 108 } 109 110 /// Collects information from the AST that is useful for the formatter 111 final class FormatVisitor : ASTVisitor 112 { 113 alias visit = ASTVisitor.visit; 114 115 /** 116 * Params: 117 * astInformation = the AST information that will be filled in 118 */ 119 this(ASTInformation* astInformation) 120 { 121 this.astInformation = astInformation; 122 } 123 124 override void visit(const ArrayInitializer arrayInitializer) 125 { 126 astInformation.arrayStartLocations ~= arrayInitializer.startLocation; 127 arrayInitializer.accept(this); 128 } 129 130 override void visit (const SharedStaticConstructor sharedStaticConstructor) 131 { 132 astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticConstructor.location; 133 sharedStaticConstructor.accept(this); 134 } 135 136 override void visit (const SharedStaticDestructor sharedStaticDestructor) 137 { 138 astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticDestructor.location; 139 sharedStaticDestructor.accept(this); 140 } 141 142 override void visit (const StaticConstructor staticConstructor) 143 { 144 astInformation.staticConstructorDestructorLocations ~= staticConstructor.location; 145 staticConstructor.accept(this); 146 } 147 148 override void visit (const StaticDestructor staticDestructor) 149 { 150 astInformation.staticConstructorDestructorLocations ~= staticDestructor.location; 151 staticDestructor.accept(this); 152 } 153 154 override void visit (const Constructor constructor) 155 { 156 astInformation.constructorDestructorLocations ~= constructor.location; 157 constructor.accept(this); 158 } 159 160 override void visit (const Destructor destructor) 161 { 162 astInformation.constructorDestructorLocations ~= destructor.index; 163 destructor.accept(this); 164 } 165 166 override void visit(const ConditionalDeclaration dec) 167 { 168 if (dec.hasElse) 169 { 170 auto condition = dec.compileCondition; 171 if (condition.versionCondition !is null) 172 { 173 astInformation.conditionalWithElseLocations 174 ~= condition.versionCondition.versionIndex; 175 } 176 else if (condition.debugCondition !is null) 177 { 178 astInformation.conditionalWithElseLocations ~= condition.debugCondition.debugIndex; 179 } 180 // Skip "static if" because the formatting for normal "if" handles 181 // it properly 182 } 183 dec.accept(this); 184 } 185 186 override void visit(const Constraint constraint) 187 { 188 astInformation.constraintLocations ~= constraint.location; 189 constraint.accept(this); 190 } 191 192 override void visit(const ConditionalStatement statement) 193 { 194 auto condition = statement.compileCondition; 195 if (condition.versionCondition !is null) 196 { 197 astInformation.conditionalStatementLocations ~= condition.versionCondition.versionIndex; 198 } 199 else if (condition.debugCondition !is null) 200 { 201 astInformation.conditionalStatementLocations ~= condition.debugCondition.debugIndex; 202 } 203 statement.accept(this); 204 } 205 206 override void visit(const FunctionLiteralExpression funcLit) 207 { 208 if (funcLit.functionBody !is null) 209 { 210 const bs = funcLit.functionBody.blockStatement; 211 212 astInformation.funLitStartLocations ~= bs.startLocation; 213 astInformation.funLitEndLocations ~= bs.endLocation; 214 astInformation.indentInfoSortedByEndLocation ~= 215 BraceIndentInfo(bs.startLocation, bs.endLocation); 216 } 217 funcLit.accept(this); 218 } 219 220 override void visit(const DefaultStatement defaultStatement) 221 { 222 astInformation.caseEndLocations ~= defaultStatement.colonLocation; 223 defaultStatement.accept(this); 224 } 225 226 override void visit(const CaseStatement caseStatement) 227 { 228 astInformation.caseEndLocations ~= caseStatement.colonLocation; 229 caseStatement.accept(this); 230 } 231 232 override void visit(const CaseRangeStatement caseRangeStatement) 233 { 234 astInformation.caseEndLocations ~= caseRangeStatement.colonLocation; 235 caseRangeStatement.accept(this); 236 } 237 238 override void visit(const FunctionBody functionBody) 239 { 240 if (functionBody.blockStatement !is null) 241 astInformation.doubleNewlineLocations ~= functionBody.blockStatement.endLocation; 242 if (functionBody.bodyStatement !is null && functionBody.bodyStatement 243 .blockStatement !is null) 244 astInformation.doubleNewlineLocations 245 ~= functionBody.bodyStatement.blockStatement.endLocation; 246 functionBody.accept(this); 247 } 248 249 override void visit(const StructInitializer structInitializer) 250 { 251 astInformation.structInitStartLocations ~= structInitializer.startLocation; 252 astInformation.structInitEndLocations ~= structInitializer.endLocation; 253 astInformation.indentInfoSortedByEndLocation ~= 254 BraceIndentInfo(structInitializer.startLocation, structInitializer.endLocation); 255 256 structInitializer.accept(this); 257 } 258 259 override void visit(const EnumBody enumBody) 260 { 261 astInformation.doubleNewlineLocations ~= enumBody.endLocation; 262 enumBody.accept(this); 263 } 264 265 override void visit(const Unittest unittest_) 266 { 267 astInformation.doubleNewlineLocations ~= unittest_.blockStatement.endLocation; 268 unittest_.accept(this); 269 } 270 271 override void visit(const Invariant invariant_) 272 { 273 astInformation.doubleNewlineLocations ~= invariant_.blockStatement.endLocation; 274 invariant_.accept(this); 275 } 276 277 override void visit(const StructBody structBody) 278 { 279 astInformation.doubleNewlineLocations ~= structBody.endLocation; 280 structBody.accept(this); 281 } 282 283 override void visit(const TemplateDeclaration templateDeclaration) 284 { 285 astInformation.doubleNewlineLocations ~= templateDeclaration.endLocation; 286 templateDeclaration.accept(this); 287 } 288 289 override void visit(const TypeSuffix typeSuffix) 290 { 291 if (typeSuffix.star.type != tok!"") 292 astInformation.spaceAfterLocations ~= typeSuffix.star.index; 293 typeSuffix.accept(this); 294 } 295 296 override void visit(const UnaryExpression unary) 297 { 298 if (unary.prefix.type == tok!"~" || unary.prefix.type == tok!"&" 299 || unary.prefix.type == tok!"*" 300 || unary.prefix.type == tok!"+" || unary.prefix.type == tok!"-") 301 { 302 astInformation.unaryLocations ~= unary.prefix.index; 303 } 304 unary.accept(this); 305 } 306 307 override void visit(const AttributeDeclaration attributeDeclaration) 308 { 309 astInformation.attributeDeclarationLines ~= attributeDeclaration.line; 310 attributeDeclaration.accept(this); 311 } 312 313 override void visit(const InStatement inStatement) 314 { 315 astInformation.contractLocations ~= inStatement.inTokenLocation; 316 inStatement.accept(this); 317 } 318 319 override void visit(const OutStatement outStatement) 320 { 321 astInformation.contractLocations ~= outStatement.outTokenLocation; 322 outStatement.accept(this); 323 } 324 325 private: 326 ASTInformation* astInformation; 327 }