github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/ast/ast.go (about) 1 // Package ast parses the clang AST output into AST structures. 2 package ast 3 4 import ( 5 "fmt" 6 "reflect" 7 "strconv" 8 "strings" 9 10 "github.com/Konstantin8105/c4go/util" 11 ) 12 13 // Node represents any node in the AST. 14 type Node interface { 15 Address() Address 16 Children() []Node 17 AddChild(node Node) 18 Position() Position 19 } 20 21 // Address contains the memory address (originally outputted as a hexadecimal 22 // string) from the clang AST. The address are not predictable between run and 23 // are only useful for identifying nodes in a single AST. 24 // 25 // The Address is used like a primary key when storing the tree as a flat 26 // structure. 27 type Address uint64 28 29 // ParseAddress returns the integer representation of the hexadecimal address 30 // (like 0x7f8a1d8ccfd0). If the address cannot be parsed, 0 is returned. 31 func ParseAddress(address string) Address { 32 addr, _ := strconv.ParseUint(address, 0, 64) 33 34 return Address(addr) 35 } 36 37 // Parse takes the coloured output of the clang AST command and returns a root 38 // node for the AST. 39 func Parse(fullline string) (returnNode Node, err error) { 40 defer func() { 41 if r := recover(); r != nil { 42 err = fmt.Errorf("cannot parse line: `%v`. %v", fullline, r) 43 returnNode = C4goErrorNode{} 44 } 45 }() 46 line := fullline 47 48 // This is a special case. I'm not sure if it's a bug in the clang AST 49 // dumper. It should have children. 50 for _, af := range arrayFillerMarkers { 51 if strings.HasPrefix(line, af) { 52 return parseArrayFiller(line), nil 53 } 54 } 55 56 parts := strings.SplitN(line, " ", 2) 57 nodeName := parts[0] 58 59 // skip node name 60 if len(parts) > 1 { 61 line = parts[1] 62 } 63 64 switch nodeName { 65 case "AccessSpecDecl": 66 return parseAccessSpecDecl(line), nil 67 case "AlignedAttr": 68 return parseAlignedAttr(line), nil 69 case "AnnotateAttr": 70 return parseAnnotateAttr(line), nil 71 case "AllocSizeAttr": 72 return parseAllocSizeAttr(line), nil 73 case "AlwaysInlineAttr": 74 return parseAlwaysInlineAttr(line), nil 75 case "ArraySubscriptExpr": 76 return parseArraySubscriptExpr(line), nil 77 case "AsmLabelAttr": 78 return parseAsmLabelAttr(line), nil 79 case "AttributedType": 80 return parseAttributedType(line), nil 81 case "AvailabilityAttr": 82 return parseAvailabilityAttr(line), nil 83 case "BuiltinAttr": 84 return parseBuiltinAttr(line), nil 85 case "BinaryConditionalOperator": 86 return parseBinaryConditionalOperator(line), nil 87 case "BinaryOperator": 88 return parseBinaryOperator(line), nil 89 case "BlockCommandComment": 90 return parseBlockCommandComment(line), nil 91 case "BreakStmt": 92 return parseBreakStmt(line), nil 93 case "BuiltinType": 94 return parseBuiltinType(line), nil 95 case "C11NoReturnAttr": 96 return parseC11NoReturnAttr(line), nil 97 case "CallExpr": 98 return parseCallExpr(line), nil 99 case "CaseStmt": 100 return parseCaseStmt(line), nil 101 case "CharacterLiteral": 102 return parseCharacterLiteral(line), nil 103 case "CompoundLiteralExpr": 104 return parseCompoundLiteralExpr(line), nil 105 case "CompoundStmt": 106 return parseCompoundStmt(line), nil 107 case "ConditionalOperator": 108 return parseConditionalOperator(line), nil 109 case "ConstAttr": 110 return parseConstAttr(line), nil 111 case "ConstantExpr": 112 return parseConstantExpr(line), nil 113 case "ConstantArrayType": 114 return parseConstantArrayType(line), nil 115 case "ContinueStmt": 116 return parseContinueStmt(line), nil 117 case "CompoundAssignOperator": 118 return parseCompoundAssignOperator(line), nil 119 case "CStyleCastExpr": 120 return parseCStyleCastExpr(line), nil 121 case "CXXConstructExpr": 122 return parseCXXConstructExpr(line), nil 123 case "CXXConstructorDecl": 124 return parseCXXConstructorDecl(line), nil 125 case "CXXMethodDecl": 126 return parseCXXMethodDecl(line), nil 127 case "CXXMemberCallExpr": 128 return parseCXXMemberCallExpr(line), nil 129 case "CXXRecord": 130 return parseCXXRecord(line), nil 131 case "CXXRecordDecl": 132 return parseCXXRecordDecl(line), nil 133 case "CXXThisExpr": 134 return parseCXXThisExpr(line), nil 135 case "DecayedType": 136 return parseDecayedType(line), nil 137 case "DeclRefExpr": 138 return parseDeclRefExpr(line), nil 139 case "DeclStmt": 140 return parseDeclStmt(line), nil 141 case "DefaultStmt": 142 return parseDefaultStmt(line), nil 143 case "DeprecatedAttr": 144 return parseDeprecatedAttr(line), nil 145 case "DisableTailCallsAttr": 146 return parseDisableTailCallsAttr(line), nil 147 case "DoStmt": 148 return parseDoStmt(line), nil 149 case "ElaboratedType": 150 return parseElaboratedType(line), nil 151 case "EmptyDecl": 152 return parseEmptyDecl(line), nil 153 case "EnableIfAttr": 154 return parseEnableIfAttr(line), nil 155 case "Enum": 156 return parseEnum(line), nil 157 case "EnumConstantDecl": 158 return parseEnumConstantDecl(line), nil 159 case "EnumDecl": 160 return parseEnumDecl(line), nil 161 case "EnumType": 162 return parseEnumType(line), nil 163 case "Field": 164 return parseField(line), nil 165 case "FieldDecl": 166 return parseFieldDecl(line), nil 167 case "FloatingLiteral": 168 return parseFloatingLiteral(line), nil 169 case "FormatArgAttr": 170 return parseFormatArgAttr(line), nil 171 case "FormatAttr": 172 return parseFormatAttr(line), nil 173 case "FunctionDecl": 174 return parseFunctionDecl(line), nil 175 case "FullComment": 176 return parseFullComment(line), nil 177 case "FunctionNoProtoType": 178 return parseFunctionNoProtoType(line), nil 179 case "FunctionProtoType": 180 return parseFunctionProtoType(line), nil 181 case "ForStmt": 182 return parseForStmt(line), nil 183 case "GenericSelectionExpr": 184 return parseGenericSelectionExpr(line), nil 185 case "HTMLStartTagComment": 186 return parseHTMLStartTagComment(line), nil 187 case "HTMLEndTagComment": 188 return parseHTMLEndTagComment(line), nil 189 case "GCCAsmStmt": 190 return parseGCCAsmStmt(line), nil 191 case "GotoStmt": 192 return parseGotoStmt(line), nil 193 case "IfStmt": 194 return parseIfStmt(line), nil 195 case "ImplicitCastExpr": 196 return parseImplicitCastExpr(line), nil 197 case "ImplicitValueInitExpr": 198 return parseImplicitValueInitExpr(line), nil 199 case "IncompleteArrayType": 200 return parseIncompleteArrayType(line), nil 201 case "IndirectFieldDecl": 202 return parseIndirectFieldDecl(line), nil 203 case "InitListExpr": 204 return parseInitListExpr(line), nil 205 case "InlineCommandComment": 206 return parseInlineCommandComment(line), nil 207 case "IntegerLiteral": 208 return parseIntegerLiteral(line), nil 209 case "LabelStmt": 210 return parseLabelStmt(line), nil 211 case "LinkageSpecDecl": 212 return parseLinkageSpecDecl(line), nil 213 case "AllocAlignAttr": 214 return parseAllocAlignAttr(line), nil 215 case "MallocAttr": 216 return parseMallocAttr(line), nil 217 case "MaxFieldAlignmentAttr": 218 return parseMaxFieldAlignmentAttr(line), nil 219 case "MemberExpr": 220 return parseMemberExpr(line), nil 221 case "ModeAttr": 222 return parseModeAttr(line), nil 223 case "NoAliasAttr": 224 return parseNoAliasAttr(line), nil 225 case "NoInlineAttr": 226 return parseNoInlineAttr(line), nil 227 case "NoThrowAttr": 228 return parseNoThrowAttr(line), nil 229 case "NonNullAttr": 230 return parseNonNullAttr(line), nil 231 case "NotTailCalledAttr": 232 return parseNotTailCalledAttr(line), nil 233 case "OffsetOfExpr": 234 return parseOffsetOfExpr(line), nil 235 case "OpaqueValueExpr": 236 return parseOpaqueValueExpr(line), nil 237 case "OverloadableAttr": 238 return parseOverloadableAttr(line), nil 239 case "PackedAttr": 240 return parsePackedAttr(line), nil 241 case "ParagraphComment": 242 return parseParagraphComment(line), nil 243 case "ParamCommandComment": 244 return parseParamCommandComment(line), nil 245 case "ParenExpr": 246 return parseParenExpr(line), nil 247 case "ParenType": 248 return parseParenType(line), nil 249 case "ParmVarDecl": 250 return parseParmVarDecl(line), nil 251 case "PointerType": 252 return parsePointerType(line), nil 253 case "PredefinedExpr": 254 return parsePredefinedExpr(line), nil 255 case "PureAttr": 256 return parsePureAttr(line), nil 257 case "QualType": 258 return parseQualType(line), nil 259 case "Record": 260 return parseRecord(line), nil 261 case "RecordDecl": 262 return parseRecordDecl(line), nil 263 case "RecordType": 264 return parseRecordType(line), nil 265 case "RestrictAttr": 266 return parseRestrictAttr(line), nil 267 case "ReturnStmt": 268 return parseReturnStmt(line), nil 269 case "ReturnsTwiceAttr": 270 return parseReturnsTwiceAttr(line), nil 271 case "SentinelAttr": 272 return parseSentinelAttr(line), nil 273 case "StaticAssertDecl": 274 return parseStaticAssertDecl(line), nil 275 case "StmtExpr": 276 return parseStmtExpr(line), nil 277 case "StringLiteral": 278 return parseStringLiteral(line), nil 279 case "SwitchStmt": 280 return parseSwitchStmt(line), nil 281 case "TextComment": 282 return parseTextComment(line), nil 283 case "TranslationUnitDecl": 284 return parseTranslationUnitDecl(line), nil 285 case "TransparentUnionAttr": 286 return parseTransparentUnionAttr(line), nil 287 case "Typedef": 288 return parseTypedef(line), nil 289 case "TypedefDecl": 290 return parseTypedefDecl(line), nil 291 case "TypedefType": 292 return parseTypedefType(line), nil 293 case "UnaryExprOrTypeTraitExpr": 294 return parseUnaryExprOrTypeTraitExpr(line), nil 295 case "UnaryOperator": 296 return parseUnaryOperator(line), nil 297 case "UnusedAttr": 298 return parseUnusedAttr(line), nil 299 case "UsedAttr": 300 return parseUsedAttr(line), nil 301 case "VAArgExpr": 302 return parseVAArgExpr(line), nil 303 case "VarDecl": 304 return parseVarDecl(line), nil 305 case "VerbatimBlockComment": 306 return parseVerbatimBlockComment(line), nil 307 case "VerbatimBlockLineComment": 308 return parseVerbatimBlockLineComment(line), nil 309 case "VerbatimLineComment": 310 return parseVerbatimLineComment(line), nil 311 case "VisibilityAttr": 312 return parseVisibilityAttr(line), nil 313 case "WarnUnusedResultAttr": 314 return parseWarnUnusedResultAttr(line), nil 315 case "WeakAttr": 316 return parseWeakAttr(line), nil 317 case "WhileStmt": 318 return parseWhileStmt(line), nil 319 case "NullStmt": 320 return nil, nil 321 } 322 return C4goErrorNode{}, fmt.Errorf("unknown node type: `%v`", fullline) 323 } 324 325 func groupsFromRegex(rx, line string) map[string]string { 326 // We remove tabs and newlines from the regex. This is purely cosmetic, 327 // as the regex input can be quite long and it's nice for the caller to 328 // be able to format it in a more readable way. 329 fullRegexp := "^(?P<address>[0-9a-fx]+) " + 330 strings.Replace(strings.Replace(rx, "\n", "", -1), "\t", "", -1) 331 rx = fullRegexp + "[\\s]*$" 332 333 re := util.GetRegex(rx) 334 335 match := re.FindStringSubmatch(line) 336 if len(match) == 0 { 337 panic("could not match regexp with string\n" + rx + "\n" + line + "\n") 338 } 339 340 result := make(map[string]string) 341 for i, name := range re.SubexpNames() { 342 if i != 0 { 343 result[name] = match[i] 344 } 345 } 346 347 return result 348 } 349 350 // GetTypeIfExist return string inside field Type of struct 351 func GetTypeIfExist(node Node) (Type *string, ok bool) { 352 for _, typ := range []string{"Type", "Type1", "Type2"} { 353 s := reflect.ValueOf(node).Elem() 354 typeOfT := s.Type() 355 for i := 0; i < s.NumField(); i++ { 356 f := s.Field(i) 357 name := typeOfT.Field(i).Name 358 if typ != name { 359 continue 360 } 361 _, ok := f.Interface().(string) 362 if !ok { 363 continue 364 } 365 str := f.Addr().Interface().(*string) 366 return str, true 367 } 368 } 369 return nil, false 370 }