github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/program/struct.go (about)

     1  package program
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/Konstantin8105/c4go/ast"
     8  )
     9  
    10  type TypeOfStruct int
    11  
    12  const (
    13  	UnionType TypeOfStruct = iota
    14  	StructType
    15  	ClassType
    16  )
    17  
    18  // Struct represents the definition for a C struct.
    19  type Struct struct {
    20  	// The name of the struct.
    21  	Name string
    22  
    23  	// IsGlobal is true for case global struct
    24  	IsGlobal bool
    25  
    26  	// This field is used to avoid to duplicate code for union case the type is the same.
    27  	Type TypeOfStruct
    28  
    29  	// Each of the fields and their C type. The field may be a string or an
    30  	// instance of Struct for nested structures.
    31  	Fields map[string]interface{}
    32  
    33  	// int    - position of field
    34  	// string - name of field
    35  	FieldNames map[int]string
    36  }
    37  
    38  // NewStruct creates a new Struct definition from an ast.RecordDecl.
    39  func NewStruct(p *Program, n *ast.RecordDecl) (st *Struct, err error) {
    40  	defer func() {
    41  		if err != nil {
    42  			err = fmt.Errorf("cannot create new structure : %T. Error : %v",
    43  				n, err)
    44  		} else {
    45  			p.Structs[n.Name] = st
    46  		}
    47  	}()
    48  	fields := make(map[string]interface{})
    49  	names := map[int]string{}
    50  
    51  	counter := 0
    52  	for _, field := range n.Children() {
    53  		switch f := field.(type) {
    54  		case *ast.FieldDecl:
    55  			fields[f.Name] = f.Type
    56  			names[counter] = f.Name
    57  
    58  		case *ast.IndirectFieldDecl:
    59  			fields[f.Name] = f.Type
    60  			names[counter] = f.Name
    61  
    62  		case *ast.RecordDecl:
    63  			fields[f.Name], err = NewStruct(p, f)
    64  			if err != nil {
    65  				return
    66  			}
    67  
    68  		case *ast.MaxFieldAlignmentAttr,
    69  			*ast.AlignedAttr,
    70  			*ast.PackedAttr,
    71  			*ast.EnumDecl,
    72  			*ast.TransparentUnionAttr,
    73  			*ast.FullComment:
    74  			// FIXME: Should these really be ignored?
    75  
    76  		default:
    77  			err = fmt.Errorf("cannot decode: %#v", f)
    78  			return
    79  		}
    80  		counter++
    81  	}
    82  
    83  	var t TypeOfStruct
    84  	switch n.Kind {
    85  	case "union":
    86  		t = UnionType
    87  	case "class":
    88  		t = ClassType
    89  	case "struct":
    90  		t = StructType
    91  	default:
    92  		err = fmt.Errorf("undefine kind of RecordDecl `%v`", n.Kind)
    93  		return
    94  	}
    95  
    96  	return &Struct{
    97  		Name:       n.Name,
    98  		IsGlobal:   p.Function == nil,
    99  		Type:       t,
   100  		Fields:     fields,
   101  		FieldNames: names,
   102  	}, nil
   103  }
   104  
   105  // IsUnion - return true if the cType is 'union' or
   106  // typedef of union
   107  func (p *Program) IsUnion(cType string) bool {
   108  	if strings.HasPrefix(cType, "union ") {
   109  		return true
   110  	}
   111  	if _, ok := p.Unions[cType]; ok {
   112  		return true
   113  	}
   114  	if _, ok := p.Unions["union "+cType]; ok {
   115  		return true
   116  	}
   117  	if _, ok := p.GetBaseTypeOfTypedef("union " + cType); ok {
   118  		return true
   119  	}
   120  	if t, ok := p.GetBaseTypeOfTypedef(cType); ok {
   121  		if t == cType {
   122  			panic(fmt.Errorf("cannot be same name: %s", t))
   123  		}
   124  		if strings.HasPrefix(t, "struct ") {
   125  			return false
   126  		}
   127  		if t == "" {
   128  			panic(fmt.Errorf("type cannot be empty"))
   129  		}
   130  		return p.IsUnion(t)
   131  	}
   132  	return false
   133  }
   134  
   135  // GetBaseTypeOfTypedef - return typedef type
   136  func (p *Program) GetBaseTypeOfTypedef(cTypedef string) (
   137  	cBase string, ok bool) {
   138  
   139  	cBase, ok = p.TypedefType[cTypedef]
   140  	if cBase == "" && ok {
   141  		panic(fmt.Errorf("type cannot be empty"))
   142  	}
   143  
   144  	if cBase == cTypedef {
   145  		panic(fmt.Errorf("typedef loop for : %s", cBase))
   146  	}
   147  
   148  	return
   149  }