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  }