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

     1  package transpiler
     2  
     3  import (
     4  	"fmt"
     5  	goast "go/ast"
     6  	"go/token"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/Konstantin8105/c4go/ast"
    11  	"github.com/Konstantin8105/c4go/program"
    12  	"github.com/Konstantin8105/c4go/types"
    13  	"github.com/Konstantin8105/c4go/util"
    14  )
    15  
    16  func transpileDeclRefExpr(n *ast.DeclRefExpr, p *program.Program) (
    17  	expr *goast.Ident, exprType string, err error) {
    18  
    19  	if n.For == "EnumConstant" {
    20  		// clang don`t show enum constant with enum type,
    21  		// so we have to use hack for repair the type
    22  		if v, ok := p.EnumConstantToEnum[n.Name]; ok {
    23  			expr, exprType, err = util.NewIdent(n.Name), v, nil
    24  			return
    25  		}
    26  	}
    27  
    28  	if name, ok := program.DefinitionVariable[n.Name]; ok {
    29  		name = p.ImportType(name)
    30  		return util.NewIdent(name), n.Type, nil
    31  	}
    32  
    33  	if n.For == "Function" {
    34  		var includeFile string
    35  		includeFile, err = p.GetIncludeFileNameByFunctionSignature(n.Name, n.Type)
    36  		p.AddMessage(p.GenerateWarningMessage(err, n))
    37  		if includeFile != "" && p.IncludeHeaderIsExists(includeFile) {
    38  			name := p.GetFunctionDefinition(n.Name).Substitution
    39  			if strings.Contains(name, ".") && !strings.Contains(name, "github") {
    40  				p.AddImport(strings.Split(name, ".")[0])
    41  			}
    42  			return goast.NewIdent(name), n.Type, nil
    43  		}
    44  	}
    45  
    46  	theType := n.Type
    47  	expr = util.NewIdent(n.Name)
    48  
    49  	return expr, theType, nil
    50  }
    51  
    52  func getDefaultValueForVar(p *program.Program, a *ast.VarDecl) (
    53  	expr []goast.Expr, _ string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
    54  	defer func() {
    55  		if err != nil {
    56  			err = fmt.Errorf("cannot getDefaultValueForVar : err = %v", err)
    57  		}
    58  	}()
    59  	if len(a.Children()) == 0 {
    60  		return nil, "", nil, nil, nil
    61  	}
    62  
    63  	defaultValue, defaultValueType, newPre, newPost, err := atomicOperation(a.Children()[0], p)
    64  	if err != nil {
    65  		return nil, defaultValueType, newPre, newPost, err
    66  	}
    67  
    68  	var values []goast.Expr
    69  	if !types.IsNullExpr(defaultValue) {
    70  		t, err := types.CastExpr(p, defaultValue, defaultValueType, a.Type)
    71  		if !p.AddMessage(p.GenerateWarningMessage(err, a)) {
    72  			values = append(values, t)
    73  			defaultValueType = a.Type
    74  		}
    75  	}
    76  
    77  	return values, defaultValueType, newPre, newPost, nil
    78  }
    79  
    80  // GenerateFuncType in according to types
    81  // Type: *ast.FuncType {
    82  // .  Func: 13:7
    83  // .  Params: *ast.FieldList {
    84  // .  .  Opening: 13:12
    85  // .  .  List: []*ast.Field (len = 2) {
    86  // .  .  .  0: *ast.Field {
    87  // .  .  .  .  Type: *ast.Ident {
    88  // .  .  .  .  .  NamePos: 13:13
    89  // .  .  .  .  .  Name: "int"
    90  // .  .  .  .  }
    91  // .  .  .  }
    92  // .  .  .  1: *ast.Field {
    93  // .  .  .  .  Type: *ast.Ident {
    94  // .  .  .  .  .  NamePos: 13:17
    95  // .  .  .  .  .  Name: "int"
    96  // .  .  .  .  }
    97  // .  .  .  }
    98  // .  .  }
    99  // .  }
   100  // .  Results: *ast.FieldList {
   101  // .  .  Opening: -
   102  // .  .  List: []*ast.Field (len = 1) {
   103  // .  .  .  0: *ast.Field {
   104  // .  .  .  .  Type: *ast.Ident {
   105  // .  .  .  .  .  NamePos: 13:21
   106  // .  .  .  .  .  Name: "string"
   107  // .  .  .  .  }
   108  // .  .  .  }
   109  // .  .  }
   110  // .  }
   111  // }
   112  func GenerateFuncType(fields, returns []string) *goast.FuncType {
   113  	var ft goast.FuncType
   114  	{
   115  		var fieldList goast.FieldList
   116  		fieldList.Opening = 1
   117  		fieldList.Closing = 2
   118  		for i := range fields {
   119  			fieldList.List = append(fieldList.List, &goast.Field{Type: &goast.Ident{Name: fields[i]}})
   120  		}
   121  		ft.Params = &fieldList
   122  	}
   123  	{
   124  		var fieldList goast.FieldList
   125  		for i := range returns {
   126  			fieldList.List = append(fieldList.List, &goast.Field{Type: &goast.Ident{Name: returns[i]}})
   127  		}
   128  		ft.Results = &fieldList
   129  	}
   130  	return &ft
   131  }
   132  
   133  // transpileInitListExpr.
   134  //
   135  // Examples:
   136  //
   137  // -InitListExpr 0x3cea0f0 <col:29, line:54:1> 'char *[256]'
   138  //
   139  //	|-array filler
   140  //	| `-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *'
   141  //	|-ImplicitCastExpr 0x3cea138 <line:51:10> 'char *' <ArrayToPointerDecay>
   142  //	| `-StringLiteral 0x3ce9f00 <col:10> 'char [3]' lvalue "fa"
   143  //	|-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *'
   144  //	|-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *'
   145  func transpileInitListExpr(e *ast.InitListExpr, p *program.Program) (
   146  	expr goast.Expr, exprType string, err error) {
   147  	defer func() {
   148  		if err != nil {
   149  			err = fmt.Errorf("cannot transpileInitListExpr. err = %v", err)
   150  		}
   151  	}()
   152  	resp := []goast.Expr{}
   153  	e.Type1 = util.GenerateCorrectType(e.Type1)
   154  	e.Type2 = util.GenerateCorrectType(e.Type2)
   155  	exprType = e.Type1
   156  
   157  	for _, node := range e.Children() {
   158  		// Skip ArrayFiller
   159  		if _, ok := node.(*ast.ArrayFiller); ok {
   160  			continue
   161  		}
   162  
   163  		// var expr goast.Expr
   164  		// var eType string
   165  		// var err error
   166  
   167  		expr, _, _, _, err := transpileToExpr(node, p, true)
   168  		p.AddMessage(p.GenerateWarningMessage(err, node))
   169  
   170  		resp = append(resp, expr)
   171  	}
   172  
   173  	goType, err := types.ResolveType(p, e.Type1)
   174  	if err != nil {
   175  		return nil, "", err
   176  	}
   177  
   178  	arrayType, arraySize := types.GetArrayTypeAndSize(e.Type1)
   179  	if arraySize > 0 {
   180  		for i := len(resp); i < arraySize; i++ {
   181  			zero, _ := zeroValue(p, arrayType)
   182  			resp = append(resp, zero)
   183  		}
   184  		exprType = arrayType + "[]"
   185  	}
   186  
   187  	structType, isStruct := p.Structs[e.Type1]
   188  	if !isStruct {
   189  		if tt, ok := p.GetBaseTypeOfTypedef(e.Type1); ok {
   190  			structType, isStruct = p.Structs[tt]
   191  		}
   192  	}
   193  	if isStruct {
   194  		for fieldPos, node := range resp {
   195  			if fieldType, ok := structType.Fields[structType.FieldNames[fieldPos]]; ok {
   196  				if ft, ok := fieldType.(string); ok {
   197  
   198  					arr, arrFieldSize := types.GetArrayTypeAndSize(ft)
   199  					if arrFieldSize > 0 {
   200  
   201  						var fixed bool
   202  						switch v := node.(type) {
   203  						case *goast.CompositeLit:
   204  							if id, ok := v.Type.(*goast.Ident); ok {
   205  								goType, err := types.ResolveType(p, arr)
   206  								p.AddMessage(p.GenerateWarningMessage(err, nil))
   207  								id.Name = fmt.Sprintf("[%d]%s", arrFieldSize, goType)
   208  								fixed = true
   209  							}
   210  						case *goast.CallExpr:
   211  							// From:
   212  							// 0  *ast.CallExpr {
   213  							// 1  .  Fun: *ast.Ident {
   214  							// 3  .  .  Name: "[]byte"
   215  							// 4  .  }
   216  							// 6  .  Args: []ast.Expr (len = 1) {
   217  							// 7  .  .  0: *ast.BasicLit {
   218  							// 9  .  .  .  Kind: STRING
   219  							// 10  .  .  .  Value: "\"dream\\x00\""
   220  							// 11  .  .  }
   221  							// 12  .  }
   222  							// 15  }
   223  							if id, ok := v.Fun.(*goast.Ident); ok && id.Name == "[]byte" {
   224  								if len(v.Args) == 1 {
   225  									if bl, ok := v.Args[0].(*goast.BasicLit); ok && bl.Kind == token.STRING {
   226  										var sl ast.StringLiteral
   227  										sl.Type = ft
   228  										sl.Value, err = strconv.Unquote(bl.Value)
   229  										p.AddMessage(p.GenerateWarningMessage(err, e))
   230  										var ex goast.Expr
   231  										ex, _, err = transpileStringLiteral(p, &sl, true)
   232  										p.AddMessage(p.GenerateWarningMessage(err, e))
   233  										resp[fieldPos] = ex
   234  										fixed = true
   235  									}
   236  								}
   237  							}
   238  						}
   239  						if !fixed {
   240  							err = fmt.Errorf("cannot fix slice to array for type : %T", expr)
   241  						}
   242  					}
   243  				}
   244  			}
   245  		}
   246  	}
   247  
   248  	if len(resp) == 1 && goType == "[]byte" {
   249  		return resp[0], exprType, nil
   250  	}
   251  
   252  	return &goast.CompositeLit{
   253  		Lbrace: 1,
   254  		Type:   goast.NewIdent(goType),
   255  		Elts:   resp,
   256  	}, exprType, nil
   257  }
   258  
   259  func zeroValue(p *program.Program, cType string) (zero goast.Expr, zeroType string) {
   260  	zeroType = cType
   261  	goType, err := types.ResolveType(p, cType)
   262  	p.AddMessage(p.GenerateWarningMessage(err, nil))
   263  
   264  	// for structs
   265  	if tt, ok := p.GetBaseTypeOfTypedef(cType); ok {
   266  		if _, ok := p.Structs[tt]; ok {
   267  			zero = goast.NewIdent(fmt.Sprintf("%s{}", goType))
   268  			return
   269  		}
   270  	}
   271  	if _, ok := p.Structs[cType]; ok {
   272  		zero = goast.NewIdent(fmt.Sprintf("%s{}", goType))
   273  		return
   274  	}
   275  
   276  	switch {
   277  	case goType == "byte":
   278  		zero = goast.NewIdent("'\\x00'")
   279  	case types.IsCPointer(cType, p):
   280  		zero = goast.NewIdent("nil")
   281  	case types.IsCArray(cType, p):
   282  		goType, err := types.ResolveType(p, cType)
   283  		p.AddMessage(p.GenerateWarningMessage(err, nil))
   284  		zero = &goast.CompositeLit{
   285  			Lbrace: 1,
   286  			Type:   goast.NewIdent(goType),
   287  		}
   288  	default:
   289  		zero = goast.NewIdent("0")
   290  	}
   291  
   292  	return
   293  }
   294  
   295  func transpileDeclStmt(n *ast.DeclStmt, p *program.Program) (
   296  	stmts []goast.Stmt, err error) {
   297  
   298  	if len(n.Children()) == 0 {
   299  		return
   300  	}
   301  	var tud ast.TranslationUnitDecl
   302  	tud.ChildNodes = n.Children()
   303  	var decls []goast.Decl
   304  	decls, err = transpileToNode(&tud, p)
   305  	if err != nil {
   306  		p.AddMessage(p.GenerateWarningMessage(err, n))
   307  		err = nil
   308  	}
   309  	stmts = convertDeclToStmt(decls)
   310  
   311  	return
   312  }
   313  
   314  func transpileArraySubscriptExpr(n *ast.ArraySubscriptExpr, p *program.Program) (
   315  	_ *goast.IndexExpr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   316  	defer func() {
   317  		if err != nil {
   318  			err = fmt.Errorf("cannot transpile ArraySubscriptExpr. err = %v", err)
   319  			p.AddMessage(p.GenerateWarningMessage(err, n))
   320  		}
   321  	}()
   322  
   323  	children := n.Children()
   324  
   325  	if un, ok := children[1].(*ast.UnaryOperator); ok && un.Operator == "-" && un.IsPrefix {
   326  		// from:
   327  		//  ArraySubscriptExpr 'double' lvalue
   328  		//  |-ImplicitCastExpr 'double *' <LValueToRValue>
   329  		//  | `-DeclRefExpr 'double *' lvalue Var 0x2d19e58 'p' 'double *'
   330  		//  `-UnaryOperator 'int' prefix '-'
   331  		//    `-IntegerLiteral 'int' 1
   332  		// to:
   333  		//  BinaryOperator 'double *' '-'
   334  		//  |-ImplicitCastExpr 'double *' <LValueToRValue>
   335  		//  | `-DeclRefExpr 'double *' lvalue Var 0x2d19e58 'p' 'double *'
   336  		//  `-IntegerLiteral 'int' 1
   337  
   338  		t, ok := ast.GetTypeIfExist(children[0])
   339  		if ok {
   340  			bin := &ast.BinaryOperator{
   341  				Type:     *t,
   342  				Operator: "-",
   343  			}
   344  			bin.AddChild(n.Children()[0])
   345  			bin.AddChild(un.Children()[0])
   346  
   347  			expression, _, newPre, newPost, err := atomicOperation(bin, p)
   348  			preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   349  
   350  			return &goast.IndexExpr{
   351  				X:     expression,
   352  				Index: goast.NewIdent("0"),
   353  			}, n.Type, preStmts, postStmts, err
   354  		}
   355  	}
   356  
   357  	expression, _, newPre, newPost, err := transpileToExpr(children[0], p, false)
   358  	if err != nil {
   359  		return nil, "", nil, nil, err
   360  	}
   361  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   362  
   363  	index, _, newPre, newPost, err := atomicOperation(children[1], p)
   364  	if err != nil {
   365  		return nil, "", nil, nil, err
   366  	}
   367  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   368  
   369  	//	index, err = types.CastExpr(p, index, indexType, "int")
   370  	//	if err != nil {
   371  	//		return nil, "", nil, nil, err
   372  	//	}
   373  	//	index = util.NewCallExpr("int", index)
   374  
   375  	return &goast.IndexExpr{
   376  		X:     expression,
   377  		Index: index,
   378  	}, n.Type, preStmts, postStmts, nil
   379  }
   380  
   381  func transpileMemberExpr(n *ast.MemberExpr, p *program.Program) (
   382  	_ goast.Expr, _ string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   383  	defer func() {
   384  		if err != nil {
   385  			err = fmt.Errorf("cannot transpile MemberExpr. err = %v", err)
   386  			p.AddMessage(p.GenerateWarningMessage(err, n))
   387  		}
   388  	}()
   389  
   390  	n.Type = util.GenerateCorrectType(n.Type)
   391  	n.Type2 = util.GenerateCorrectType(n.Type2)
   392  
   393  	originTypes := []string{n.Type, n.Type2}
   394  	if n.Children()[0] != nil {
   395  		switch v := n.Children()[0].(type) {
   396  		case *ast.ParenExpr:
   397  			originTypes = append(originTypes, v.Type)
   398  			originTypes = append(originTypes, v.Type2)
   399  		}
   400  	}
   401  
   402  	lhs, lType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false)
   403  	if err != nil {
   404  		return nil, "", nil, nil, err
   405  	}
   406  
   407  	baseType := lType
   408  	lType = util.GenerateCorrectType(lType)
   409  
   410  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   411  
   412  	// typedef
   413  
   414  	lhsTypes := [2]string{lType, lType}
   415  
   416  	if t, ok := ast.GetTypeIfExist(n.Children()[0]); ok {
   417  		lhsTypes[1] = *t
   418  	}
   419  
   420  	var structType *program.Struct
   421  	var lhsType string = lhsTypes[0]
   422  	for _, lhsTypeLocal := range lhsTypes {
   423  		// lhsType will be something like "struct foo"
   424  		structType = p.GetStruct(lhsTypeLocal)
   425  		// added for support "struct typedef"
   426  		if structType == nil {
   427  			structType = p.GetStruct("struct " + lhsTypeLocal)
   428  		}
   429  		// added for support "union typedef"
   430  		if structType == nil {
   431  			structType = p.GetStruct("union " + lhsTypeLocal)
   432  		}
   433  		// for anonymous structs
   434  		if structType == nil {
   435  			structType = p.GetStruct(baseType)
   436  		}
   437  		// for anonymous structs
   438  		if structType == nil {
   439  			structType = p.GetStruct(util.CleanCType(baseType))
   440  		}
   441  		// typedef types
   442  		if structType == nil {
   443  			structType = p.GetStruct(p.TypedefType[baseType])
   444  		}
   445  		if structType == nil {
   446  			t := types.GetBaseType(baseType)
   447  			structType = p.GetStruct(p.TypedefType[t])
   448  		}
   449  		// other case
   450  		for _, t := range originTypes {
   451  			if structType == nil {
   452  				structType = p.GetStruct(util.CleanCType(t))
   453  			} else {
   454  				break
   455  			}
   456  			if structType == nil {
   457  				structType = p.GetStruct(types.GetBaseType(t))
   458  			} else {
   459  				break
   460  			}
   461  		}
   462  
   463  		if structType != nil {
   464  			lhsType = lhsTypeLocal
   465  			break
   466  		}
   467  	}
   468  
   469  	if n.Name == "" {
   470  		n.Name = generateNameFieldDecl(util.GenerateCorrectType(n.Type))
   471  	}
   472  	rhs := n.Name
   473  	rhsType := "void *"
   474  	if structType == nil {
   475  		// This case should not happen in the future. Any structs should be
   476  		// either parsed correctly from the source or be manually setup when the
   477  		// parser starts if the struct if hidden or shared between libraries.
   478  		//
   479  		// Some other things to keep in mind:
   480  		//   1. Types need to be stripped of their pointer, 'FILE *' -> 'FILE'.
   481  		//   2. Types may refer to one or more other types in a chain that have
   482  		//      to be resolved before the real field type can be determined.
   483  		err = fmt.Errorf("cannot determine type for LHS '%v'"+
   484  			", will use 'void *' for all fields. Is lvalue = %v. n.Name = %v. "+
   485  			"Position = %v",
   486  			lhsTypes, n.IsLvalue, n.Name, n.Pos)
   487  		p.AddMessage(p.GenerateWarningMessage(err, n))
   488  		err = nil // ignore error
   489  	} else {
   490  		if s, ok := structType.Fields[rhs].(string); ok {
   491  			rhsType = s
   492  		} else {
   493  			err = fmt.Errorf("cannot determine type for RHS '%v' of '%s', will use"+
   494  				" 'void *' for all fields. Is lvalue = %v. n.Name = `%v`",
   495  				rhs, structType.Name, n.IsLvalue, n.Name)
   496  			p.AddMessage(p.GenerateWarningMessage(err, n))
   497  			err = nil // ignore error
   498  		}
   499  	}
   500  
   501  	x := lhs
   502  	if n.IsPointer {
   503  		x = &goast.IndexExpr{X: x, Index: util.NewIntLit(0)}
   504  	}
   505  
   506  	// Check for member name translation.
   507  	lhsType = strings.TrimSpace(lhsType)
   508  	if lhsType[len(lhsType)-1] == '*' {
   509  		lhsType = lhsType[:len(lhsType)-len(" *")]
   510  	}
   511  	if str := p.GetStruct("c4go_" + lhsType); str != nil {
   512  		if alias, ok := str.Fields[rhs]; ok {
   513  			// change type
   514  			if str, ok := p.Structs[lhsType]; ok {
   515  				if name, ok := str.Fields[rhs].(string); ok {
   516  					n.Type = name
   517  				}
   518  			}
   519  			// change field
   520  			rhs = alias.(string)
   521  			goto Selector
   522  		}
   523  	}
   524  
   525  	// anonymous struct member?
   526  	if rhs == "" {
   527  		rhs = "anon"
   528  	}
   529  
   530  	if isUnionMemberExpr(p, n) {
   531  		return &goast.ParenExpr{
   532  			Lparen: 1,
   533  			X: &goast.StarExpr{
   534  				Star: 1,
   535  				X: &goast.CallExpr{
   536  					Fun: &goast.SelectorExpr{
   537  						X:   x,
   538  						Sel: util.NewIdent(rhs),
   539  					},
   540  					Lparen: 1,
   541  				},
   542  			},
   543  		}, n.Type, preStmts, postStmts, nil
   544  	}
   545  
   546  Selector:
   547  	_ = rhsType
   548  
   549  	return &goast.SelectorExpr{
   550  		X:   x,
   551  		Sel: util.NewIdent(rhs),
   552  	}, n.Type, preStmts, postStmts, nil
   553  }
   554  
   555  // transpileImplicitValueInitExpr.
   556  //
   557  // Examples:
   558  //
   559  //	|-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *'
   560  func transpileImplicitValueInitExpr(n *ast.ImplicitValueInitExpr, p *program.Program) (
   561  	expr goast.Expr, exprType string, _ []goast.Stmt, _ []goast.Stmt, err error) {
   562  
   563  	defer func() {
   564  		if err != nil {
   565  			err = fmt.Errorf("cannot transpileImplicitValueInitExpr. err = %v", err)
   566  		}
   567  	}()
   568  	expr, exprType = zeroValue(p, n.Type1)
   569  	return
   570  
   571  }