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

     1  package transpiler
     2  
     3  import (
     4  	"fmt"
     5  	goast "go/ast"
     6  
     7  	"github.com/Konstantin8105/c4go/ast"
     8  	"github.com/Konstantin8105/c4go/program"
     9  	"github.com/Konstantin8105/c4go/types"
    10  	"github.com/Konstantin8105/c4go/util"
    11  )
    12  
    13  func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, exprIsStmt bool) (
    14  	expr goast.Expr,
    15  	exprType string,
    16  	preStmts []goast.Stmt,
    17  	postStmts []goast.Stmt,
    18  	err error) {
    19  	defer func() {
    20  		if err != nil {
    21  			err = fmt.Errorf("cannot transpileImplicitCastExpr. err = %v", err)
    22  		}
    23  		if exprType == "" {
    24  			exprType = "ImplicitCastExprWrongType"
    25  		}
    26  	}()
    27  
    28  	n.Type = util.GenerateCorrectType(n.Type)
    29  	n.Type2 = util.GenerateCorrectType(n.Type2)
    30  
    31  	if n.Kind == ast.CStyleCastExprNullToPointer {
    32  		expr = goast.NewIdent("nil")
    33  		exprType = types.NullPointer
    34  		return
    35  	}
    36  
    37  	// avoid unsigned overflow
    38  	// ImplicitCastExpr 0x2e649b8 <col:6, col:7> 'unsigned int' <IntegralCast>
    39  	// `-UnaryOperator 0x2e64998 <col:6, col:7> 'int' prefix '-'
    40  	if types.IsCUnsignedType(n.Type) {
    41  		if un, ok := n.Children()[0].(*ast.UnaryOperator); ok && un.Operator == "-" {
    42  			un.Type = n.Type
    43  		}
    44  	}
    45  
    46  	expr, exprType, preStmts, postStmts, err = transpileToExpr(
    47  		n.Children()[0], p, exprIsStmt)
    48  	if err != nil {
    49  		return nil, "", nil, nil, err
    50  	}
    51  	if exprType == types.NullPointer {
    52  		expr = goast.NewIdent("nil")
    53  		return
    54  	}
    55  
    56  	// avoid cast to qsort type function
    57  	if n.Type == "__compar_fn_t" {
    58  		return
    59  	}
    60  
    61  	// type casting
    62  	if n.Kind == "BitCast" && types.IsPointer(exprType, p) && types.IsPointer(n.Type, p) {
    63  		var newPost []goast.Stmt
    64  		expr, exprType, newPost, err = PntBitCast(expr, exprType, n.Type, p)
    65  		postStmts = append(postStmts, newPost...)
    66  		if err != nil {
    67  			return nil, "BitCastWrongType", nil, nil, err
    68  		}
    69  		return
    70  	}
    71  
    72  	if n.Kind == "IntegralToPointer" {
    73  		// ImplicitCastExpr 'double *' <IntegralToPointer>
    74  		// `-ImplicitCastExpr 'long' <LValueToRValue>
    75  		//   `-DeclRefExpr 'long' lvalue Var 0x30e91d8 'pnt' 'long'
    76  		if types.IsCPointer(n.Type, p) {
    77  			if t, ok := ast.GetTypeIfExist(n.Children()[0]); ok {
    78  				//
    79  				// ImplicitCastExpr 'char *' <IntegralToPointer>
    80  				// `-ImplicitCastExpr 'char' <LValueToRValue>
    81  				//   `-ArraySubscriptExpr 'char' lvalue
    82  				//     |-ImplicitCastExpr 'char *' <LValueToRValue>
    83  				//     | `-DeclRefExpr 'char *' lvalue Var 0x413c8a8 'b' 'char *'
    84  				//     `-IntegerLiteral 'int' 3
    85  				//
    86  				// n.Type = 'char *'
    87  				// *t     = 'char'
    88  				//
    89  
    90  				if ind, ok := expr.(*goast.IndexExpr); ok {
    91  					// from :
    92  					//
    93  					// 0  *ast.IndexExpr {
    94  					// 1  .  X: *ast.Ident {
    95  					// 3  .  .  Name: "b"
    96  					// 4  .  }
    97  					// 6  .  Index: *ast.BasicLit { ... }
    98  					// 12  }
    99  					//
   100  					// to:
   101  					//
   102  					// 88  0: *ast.SliceExpr {
   103  					// 89  .  X: *ast.Ident {
   104  					// 91  .  .  Name: "b"
   105  					// 93  .  }
   106  					// 95  .  Low: *ast.BasicLit { ... }
   107  					// 99  .  }
   108  					// 102  }
   109  					expr = &goast.SliceExpr{
   110  						X:      ind.X,
   111  						Low:    ind.Index,
   112  						Slice3: false,
   113  					}
   114  					exprType = n.Type
   115  					return
   116  				} else if types.IsCInteger(p, *t) {
   117  					resolveType := n.Type
   118  					resolveType, err = types.ResolveType(p, n.Type)
   119  					if err != nil {
   120  						return nil, "", nil, nil, err
   121  					}
   122  					expr = &goast.StarExpr{
   123  						X: &goast.ParenExpr{
   124  							X: &goast.CallExpr{
   125  								Fun: &goast.ParenExpr{X: goast.NewIdent("*" + resolveType)},
   126  								Args: []goast.Expr{
   127  									&goast.CallExpr{
   128  										Fun: goast.NewIdent("unsafe.Pointer"),
   129  										Args: []goast.Expr{
   130  											&goast.CallExpr{
   131  												Fun:  goast.NewIdent("uintptr"),
   132  												Args: []goast.Expr{expr},
   133  											},
   134  										},
   135  									},
   136  								},
   137  							},
   138  						},
   139  					}
   140  					p.GenerateWarningMessage(
   141  						fmt.Errorf("used unsafe convert from integer to pointer"), n)
   142  					exprType = n.Type
   143  					return
   144  				}
   145  			}
   146  		}
   147  	}
   148  
   149  	var cast bool = true
   150  	if in, ok := n.Children()[0].(*ast.IntegerLiteral); ok && in.Type == "int" {
   151  		if types.IsCInteger(p, n.Type) || types.IsCFloat(p, n.Type) {
   152  			cast = false
   153  			exprType = n.Type
   154  		}
   155  	}
   156  
   157  	if len(n.Type) != 0 && len(n.Type2) != 0 && n.Type != n.Type2 && cast {
   158  		var tt string
   159  		tt, err = types.ResolveType(p, n.Type)
   160  		if err != nil && n.Type2 != "" {
   161  			tt, err = types.ResolveType(p, n.Type2)
   162  		}
   163  		expr = util.NewCallExpr(tt, expr)
   164  		exprType = n.Type
   165  		return
   166  	}
   167  
   168  	if util.IsFunction(exprType) {
   169  		cast = false
   170  	}
   171  	if n.Kind == ast.ImplicitCastExprArrayToPointerDecay {
   172  		cast = false
   173  	}
   174  	if n.Kind == "PointerToIntegral" {
   175  		cast = false
   176  	}
   177  
   178  	if cast {
   179  		expr, err = types.CastExpr(p, expr, exprType, n.Type)
   180  		if err != nil {
   181  			return nil, "", nil, nil, err
   182  		}
   183  		exprType = n.Type
   184  	}
   185  
   186  	// Convert from struct member array to slice
   187  	// ImplicitCastExpr 'char *' <ArrayToPointerDecay>
   188  	// `-MemberExpr 'char [20]' lvalue .input_str 0x3662ba0
   189  	//   `-DeclRefExpr 'struct s_inp':'struct s_inp' lvalue Var 0x3662c50 's' 'struct s_inp':'struct s_inp'
   190  	if types.IsCPointer(n.Type, p) {
   191  		if len(n.Children()) > 0 {
   192  			if memb, ok := n.Children()[0].(*ast.MemberExpr); ok && types.IsCArray(memb.Type, p) {
   193  				expr = &goast.SliceExpr{
   194  					X:      expr,
   195  					Lbrack: 1,
   196  					Slice3: false,
   197  				}
   198  			}
   199  		}
   200  	}
   201  
   202  	return
   203  }
   204  
   205  func transpileCStyleCastExpr(n *ast.CStyleCastExpr, p *program.Program, exprIsStmt bool) (
   206  	expr goast.Expr,
   207  	exprType string,
   208  	preStmts []goast.Stmt,
   209  	postStmts []goast.Stmt,
   210  	err error) {
   211  	defer func() {
   212  		if err != nil {
   213  			err = fmt.Errorf("cannot transpileImplicitCastExpr. err = %v", err)
   214  		}
   215  		if exprType == "" {
   216  			exprType = "CStyleCastExpr"
   217  		}
   218  	}()
   219  
   220  	n.Type = util.GenerateCorrectType(n.Type)
   221  	n.Type2 = util.GenerateCorrectType(n.Type2)
   222  
   223  	// Char overflow
   224  	// example for byte(-1)
   225  	// CStyleCastExpr 0x365f628 <col:12, col:23> 'char' <IntegralCast>
   226  	// `-ParenExpr 0x365f608 <col:18, col:23> 'int'
   227  	//   `-ParenExpr 0x365f5a8 <col:19, col:22> 'int'
   228  	//     `-UnaryOperator 0x365f588 <col:20, col:21> 'int' prefix '-'
   229  	//       `-IntegerLiteral 0x365f568 <col:21> 'int' 1
   230  	if n.Type == "char" {
   231  		if par, ok := n.Children()[0].(*ast.ParenExpr); ok {
   232  			if par2, ok := par.Children()[0].(*ast.ParenExpr); ok {
   233  				if u, ok := par2.Children()[0].(*ast.UnaryOperator); ok && u.IsPrefix {
   234  					if _, ok := u.Children()[0].(*ast.IntegerLiteral); ok {
   235  						return transpileToExpr(&ast.BinaryOperator{
   236  							Type:     "int",
   237  							Type2:    "int",
   238  							Operator: "+",
   239  							ChildNodes: []ast.Node{
   240  								u,
   241  								&ast.IntegerLiteral{
   242  									Type:  "int",
   243  									Value: "256",
   244  								},
   245  							},
   246  						}, p, false)
   247  					}
   248  				}
   249  			}
   250  		}
   251  	}
   252  
   253  	if n.Kind == ast.CStyleCastExprNullToPointer {
   254  		expr = goast.NewIdent("nil")
   255  		exprType = types.NullPointer
   256  		return
   257  	}
   258  
   259  	expr, exprType, preStmts, postStmts, err = atomicOperation(
   260  		n.Children()[0], p)
   261  	if err != nil {
   262  		return nil, "", nil, nil, err
   263  	}
   264  
   265  	if exprType == types.NullPointer {
   266  		expr = goast.NewIdent("nil")
   267  		return
   268  	}
   269  
   270  	//
   271  	// struct sqlite3_pcache_page {
   272  	//   void *pBuf;        /* The content of the page */
   273  	//   void *pExtra;      /* Extra information associated with the page */
   274  	// };
   275  	//
   276  	// *(void **)pPage->page.pExtra = 0;
   277  	//
   278  	// UnaryOperator 'void *' lvalue prefix '*'
   279  	// `-CStyleCastExpr 'void **' <BitCast>
   280  	//   `-ImplicitCastExpr 'void *' <LValueToRValue>
   281  	//     `-MemberExpr 'void *' lvalue .pExtra 0x2876098
   282  	//       `-MemberExpr 'sqlite3_pcache_page':'struct sqlite3_pcache_page' lvalue ->page 0x2bdc9d0
   283  	//         `-ImplicitCastExpr 'PgHdr1 *' <LValueToRValue>
   284  	//           `-DeclRefExpr 'PgHdr1 *' lvalue Var 0x2bf5cd0 'pPage' 'PgHdr1 *'
   285  	//
   286  	// BinaryOperator 'const char **' '='
   287  	// |-DeclRefExpr 'const char **' lvalue Var 0x39a4380 'non_options' 'const char **'
   288  	// `-CStyleCastExpr 'const char **' <BitCast>
   289  	//   `-ImplicitCastExpr 'void *' <LValueToRValue>
   290  	//     `-DeclRefExpr 'void *' lvalue Var 0x39a62b0 'tmp' 'void *'
   291  	//
   292  	// type casting
   293  	if n.Kind == "BitCast" && types.IsPointer(exprType, p) && types.IsPointer(n.Type, p) {
   294  		var newPost []goast.Stmt
   295  		expr, exprType, newPost, err = PntBitCast(expr, exprType, n.Type, p)
   296  		postStmts = append(postStmts, newPost...)
   297  		if err != nil {
   298  			return nil, "BitCastWrongType", nil, nil, err
   299  		}
   300  		return
   301  	}
   302  
   303  	if len(n.Type) != 0 && len(n.Type2) != 0 && n.Type != n.Type2 {
   304  		var tt string
   305  		tt, err = types.ResolveType(p, n.Type)
   306  		if err != nil {
   307  			// `-CStyleCastExpr 0x9b32c0 <> '__clock_t':'long' <IntegralCast>
   308  			//   `-IntegerLiteral 0x9b3290 <> 'int' 1000000
   309  			tt, err = types.ResolveType(p, n.Type2)
   310  		}
   311  		expr = util.NewCallExpr(tt, expr)
   312  		exprType = n.Type
   313  		return
   314  	}
   315  
   316  	if n.Kind == ast.CStyleCastExprToVoid {
   317  		exprType = types.ToVoid
   318  		return
   319  	}
   320  
   321  	if !util.IsFunction(exprType) &&
   322  		n.Kind != ast.ImplicitCastExprArrayToPointerDecay &&
   323  		n.Kind != "PointerToIntegral" {
   324  		expr, err = types.CastExpr(p, expr, exprType, n.Type)
   325  		if err != nil {
   326  			return nil, "", nil, nil, err
   327  		}
   328  		exprType = n.Type
   329  	}
   330  
   331  	// CStyleCastExpr 'int' <PointerToIntegral>
   332  	// `-UnaryOperator 'long *' prefix '&'
   333  	//   `-DeclRefExpr 'long' lvalue Var 0x42b5268 'l' 'long'
   334  	//
   335  	// CStyleCastExpr 'int' <PointerToIntegral>
   336  	// `-ParenExpr 'long *'
   337  	//   `-UnaryOperator 'long *' prefix '&'
   338  	//     `-DeclRefExpr 'long' lvalue Var 0x38cb568 'l' 'long'
   339  	if len(n.Children()) > 0 {
   340  		if types.IsCInteger(p, n.Type) {
   341  			if t, ok := ast.GetTypeIfExist(n.Children()[0]); ok {
   342  				if types.IsPointer(*t, p) {
   343  					// main information	: https://go101.org/article/unsafe.html
   344  					sizeof, err := types.SizeOf(p, types.GetBaseType(*t))
   345  					if err != nil {
   346  						return nil, "", nil, nil, err
   347  					}
   348  					var retType string = "long long"
   349  					var newPost []goast.Stmt
   350  					expr, newPost, err = GetPointerAddress(p, expr, *t, sizeof)
   351  					if err != nil {
   352  						return nil, "", nil, nil, err
   353  					}
   354  					postStmts = append(postStmts, newPost...)
   355  
   356  					expr, err = types.CastExpr(p, expr, retType, n.Type)
   357  					if err != nil {
   358  						return nil, "", nil, nil, err
   359  					}
   360  
   361  					exprType = n.Type
   362  				}
   363  			}
   364  		}
   365  	}
   366  
   367  	return
   368  }