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 /// AST information that is needed by the formatter. 12 struct ASTInformation 13 { 14 /// Sorts the arrays so that binary search will work on them 15 void cleanup() 16 { 17 import std.algorithm : sort; 18 19 sort(doubleNewlineLocations); 20 sort(spaceAfterLocations); 21 sort(unaryLocations); 22 sort(attributeDeclarationLines); 23 sort(caseEndLocations); 24 sort(structInitStartLocations); 25 sort(structInitEndLocations); 26 sort(funLitStartLocations); 27 sort(funLitEndLocations); 28 sort(conditionalWithElseLocations); 29 sort(conditionalStatementLocations); 30 sort(arrayStartLocations); 31 sort(contractLocations); 32 sort(constraintLocations); 33 } 34 35 /// Locations of end braces for struct bodies 36 size_t[] doubleNewlineLocations; 37 38 /// Locations of tokens where a space is needed (such as the '*' in a type) 39 size_t[] spaceAfterLocations; 40 41 /// Locations of unary operators 42 size_t[] unaryLocations; 43 44 /// Lines containing attribute declarations 45 size_t[] attributeDeclarationLines; 46 47 /// Case statement colon locations 48 size_t[] caseEndLocations; 49 50 /// Opening braces of struct initializers 51 size_t[] structInitStartLocations; 52 53 /// Closing braces of struct initializers 54 size_t[] structInitEndLocations; 55 56 /// Opening braces of function literals 57 size_t[] funLitStartLocations; 58 59 /// Closing braces of function literals 60 size_t[] funLitEndLocations; 61 62 /// Conditional statements that have matching "else" statements 63 size_t[] conditionalWithElseLocations; 64 65 /// Conditional statement locations 66 size_t[] conditionalStatementLocations; 67 68 /// Locations of start locations of array initializers 69 size_t[] arrayStartLocations; 70 71 /// Locations of "in" and "out" tokens that begin contracts 72 size_t[] contractLocations; 73 74 /// Locations of template constraint "if" tokens 75 size_t[] constraintLocations; 76 } 77 78 /// Collects information from the AST that is useful for the formatter 79 final class FormatVisitor : ASTVisitor 80 { 81 /** 82 * Params: 83 * astInformation = the AST information that will be filled in 84 */ 85 this(ASTInformation* astInformation) 86 { 87 this.astInformation = astInformation; 88 } 89 90 override void visit(const ArrayInitializer arrayInitializer) 91 { 92 astInformation.arrayStartLocations ~= arrayInitializer.startLocation; 93 arrayInitializer.accept(this); 94 } 95 96 override void visit(const ConditionalDeclaration dec) 97 { 98 if (dec.hasElse) 99 { 100 auto condition = dec.compileCondition; 101 if (condition.versionCondition !is null) 102 { 103 astInformation.conditionalWithElseLocations 104 ~= condition.versionCondition.versionIndex; 105 } 106 else if (condition.debugCondition !is null) 107 { 108 astInformation.conditionalWithElseLocations ~= condition.debugCondition.debugIndex; 109 } 110 // Skip "static if" because the formatting for normal "if" handles 111 // it properly 112 } 113 dec.accept(this); 114 } 115 116 override void visit(const Constraint constraint) 117 { 118 astInformation.constraintLocations ~= constraint.location; 119 constraint.accept(this); 120 } 121 122 override void visit(const ConditionalStatement statement) 123 { 124 auto condition = statement.compileCondition; 125 if (condition.versionCondition !is null) 126 { 127 astInformation.conditionalStatementLocations ~= condition.versionCondition.versionIndex; 128 } 129 else if (condition.debugCondition !is null) 130 { 131 astInformation.conditionalStatementLocations ~= condition.debugCondition.debugIndex; 132 } 133 statement.accept(this); 134 } 135 136 override void visit(const FunctionLiteralExpression funcLit) 137 { 138 if (funcLit.functionBody !is null) 139 { 140 astInformation.funLitStartLocations ~= funcLit.functionBody.blockStatement.startLocation; 141 astInformation.funLitEndLocations ~= funcLit.functionBody.blockStatement.endLocation; 142 } 143 funcLit.accept(this); 144 } 145 146 override void visit(const DefaultStatement defaultStatement) 147 { 148 astInformation.caseEndLocations ~= defaultStatement.colonLocation; 149 defaultStatement.accept(this); 150 } 151 152 override void visit(const CaseStatement caseStatement) 153 { 154 astInformation.caseEndLocations ~= caseStatement.colonLocation; 155 caseStatement.accept(this); 156 } 157 158 override void visit(const CaseRangeStatement caseRangeStatement) 159 { 160 astInformation.caseEndLocations ~= caseRangeStatement.colonLocation; 161 caseRangeStatement.accept(this); 162 } 163 164 override void visit(const FunctionBody functionBody) 165 { 166 if (functionBody.blockStatement !is null) 167 astInformation.doubleNewlineLocations ~= functionBody.blockStatement.endLocation; 168 if (functionBody.bodyStatement !is null && functionBody.bodyStatement 169 .blockStatement !is null) 170 astInformation.doubleNewlineLocations 171 ~= functionBody.bodyStatement.blockStatement.endLocation; 172 functionBody.accept(this); 173 } 174 175 override void visit(const StructInitializer structInitializer) 176 { 177 astInformation.structInitStartLocations ~= structInitializer.startLocation; 178 astInformation.structInitEndLocations ~= structInitializer.endLocation; 179 structInitializer.accept(this); 180 } 181 182 override void visit(const EnumBody enumBody) 183 { 184 astInformation.doubleNewlineLocations ~= enumBody.endLocation; 185 enumBody.accept(this); 186 } 187 188 override void visit(const Unittest unittest_) 189 { 190 astInformation.doubleNewlineLocations ~= unittest_.blockStatement.endLocation; 191 unittest_.accept(this); 192 } 193 194 override void visit(const Invariant invariant_) 195 { 196 astInformation.doubleNewlineLocations ~= invariant_.blockStatement.endLocation; 197 invariant_.accept(this); 198 } 199 200 override void visit(const StructBody structBody) 201 { 202 astInformation.doubleNewlineLocations ~= structBody.endLocation; 203 structBody.accept(this); 204 } 205 206 override void visit(const TemplateDeclaration templateDeclaration) 207 { 208 astInformation.doubleNewlineLocations ~= templateDeclaration.endLocation; 209 templateDeclaration.accept(this); 210 } 211 212 override void visit(const TypeSuffix typeSuffix) 213 { 214 if (typeSuffix.star.type != tok!"") 215 astInformation.spaceAfterLocations ~= typeSuffix.star.index; 216 typeSuffix.accept(this); 217 } 218 219 override void visit(const UnaryExpression unary) 220 { 221 if (unary.prefix.type == tok!"~" || unary.prefix.type == tok!"&" 222 || unary.prefix.type == tok!"*" 223 || unary.prefix.type == tok!"+" || unary.prefix.type == tok!"-") 224 { 225 astInformation.unaryLocations ~= unary.prefix.index; 226 } 227 unary.accept(this); 228 } 229 230 override void visit(const AttributeDeclaration attributeDeclaration) 231 { 232 astInformation.attributeDeclarationLines ~= attributeDeclaration.line; 233 attributeDeclaration.accept(this); 234 } 235 236 override void visit(const InStatement inStatement) 237 { 238 astInformation.contractLocations ~= inStatement.inTokenLocation; 239 inStatement.accept(this); 240 } 241 242 override void visit(const OutStatement outStatement) 243 { 244 astInformation.contractLocations ~= outStatement.outTokenLocation; 245 outStatement.accept(this); 246 } 247 248 private: 249 ASTInformation* astInformation; 250 alias visit = ASTVisitor.visit; 251 }