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

     1  // This file contains functions for transpiling unary operator expressions.
     2  
     3  package transpiler
     4  
     5  import (
     6  	"fmt"
     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  	goast "go/ast"
    16  	"go/token"
    17  )
    18  
    19  func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operator token.Token) (
    20  	expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
    21  	defer func() {
    22  		if err != nil {
    23  			err = fmt.Errorf("cannot transpileUnaryOperatorInc. err = %v", err)
    24  		}
    25  		if eType == "" {
    26  			eType = "EmptyTypeInUnaryOperatorInc"
    27  		}
    28  	}()
    29  
    30  	if !(operator == token.INC || operator == token.DEC) {
    31  		err = fmt.Errorf("not acceptable operator '%v'", operator)
    32  		return
    33  	}
    34  
    35  	// for values
    36  	if v, ok := n.Children()[0].(*ast.DeclRefExpr); ok &&
    37  		!types.IsPointer(v.Type, p) {
    38  		switch n.Operator {
    39  		case "++":
    40  			return &goast.BinaryExpr{
    41  				X:  util.NewIdent(v.Name),
    42  				Op: token.ADD_ASSIGN,
    43  				Y:  &goast.BasicLit{Kind: token.INT, Value: "1"},
    44  			}, n.Type, nil, nil, nil
    45  		case "--":
    46  			return &goast.BinaryExpr{
    47  				X:  util.NewIdent(v.Name),
    48  				Op: token.SUB_ASSIGN,
    49  				Y:  &goast.BasicLit{Kind: token.INT, Value: "1"},
    50  			}, n.Type, nil, nil, nil
    51  		}
    52  	}
    53  
    54  	// for other case
    55  	op := "+"
    56  	if operator == token.DEC {
    57  		op = "-"
    58  	}
    59  
    60  	if len(n.ChildNodes) != 1 {
    61  		err = fmt.Errorf("not enought ChildNodes: %d", len(n.ChildNodes))
    62  		return
    63  	}
    64  
    65  	if !types.IsPointer(n.Type, p) {
    66  
    67  		binaryOperator := "+="
    68  		if operator == token.DEC {
    69  			binaryOperator = "-="
    70  		}
    71  
    72  		return transpileBinaryOperator(&ast.BinaryOperator{
    73  			Type:     n.Type,
    74  			Operator: binaryOperator,
    75  			ChildNodes: []ast.Node{
    76  				n.ChildNodes[0],
    77  				&ast.IntegerLiteral{
    78  					Type:  "int",
    79  					Value: "1",
    80  				},
    81  			},
    82  		}, p, false)
    83  	}
    84  
    85  	// from:
    86  	// 		*w++
    87  	// to:
    88  	// 		func () []byte {
    89  	//			defer func(){
    90  	//				*w = *w + 1 // binary
    91  	//			}()
    92  	//			tempVar := *w
    93  	//			return tempVar
    94  	// 		}
    95  	varName := "tempVarUnary"
    96  
    97  	v, vType, _, _, _ := transpileToExpr(n.ChildNodes[0], p, false)
    98  	incExpr, _, newPre, newPost, err := transpileBinaryOperator(&ast.BinaryOperator{
    99  		Type:     n.Type,
   100  		Operator: "=",
   101  		ChildNodes: []ast.Node{
   102  			n.ChildNodes[0],
   103  			&ast.BinaryOperator{
   104  				Type:     n.Type,
   105  				Operator: op,
   106  				ChildNodes: append(n.ChildNodes, &ast.IntegerLiteral{
   107  					Type:  "int",
   108  					Value: "1",
   109  				}),
   110  			},
   111  		},
   112  	}, p, false)
   113  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   114  	if err != nil {
   115  		return
   116  	}
   117  
   118  	var exprResolveType string
   119  	exprResolveType, err = types.ResolveType(p, vType)
   120  	if err != nil {
   121  		return
   122  	}
   123  
   124  	expr = util.NewAnonymousFunction(
   125  		// body :
   126  		append(preStmts, &goast.AssignStmt{
   127  			Lhs: []goast.Expr{util.NewIdent(varName)},
   128  			Tok: token.DEFINE,
   129  			Rhs: []goast.Expr{v},
   130  		}),
   131  		// defer :
   132  		[]goast.Stmt{
   133  			&goast.ExprStmt{X: incExpr},
   134  		},
   135  		// return :
   136  		util.NewIdent(varName),
   137  		exprResolveType)
   138  
   139  	eType = n.Type
   140  
   141  	return
   142  }
   143  
   144  func transpileUnaryOperatorNot(n *ast.UnaryOperator, p *program.Program) (
   145  	goast.Expr, string, []goast.Stmt, []goast.Stmt, error) {
   146  	e, eType, preStmts, postStmts, err := atomicOperation(n.Children()[0], p)
   147  	if err != nil {
   148  		return nil, "", nil, nil, err
   149  	}
   150  
   151  	// UnaryOperator <> 'int' prefix '!'
   152  	// `-ImplicitCastExpr <> 'int (*)(int, double)' <LValueToRValue>
   153  	//   `-DeclRefExpr <> 'int (*)(int, double)' lvalue Var 0x2be4e80 'T' 'int (*)(int, double)'
   154  	if util.IsFunction(eType) {
   155  		return &goast.BinaryExpr{
   156  			X:  e,
   157  			Op: token.EQL, // ==
   158  			Y:  goast.NewIdent("nil"),
   159  		}, "bool", preStmts, postStmts, nil
   160  	}
   161  
   162  	// specific case:
   163  	//
   164  	// UnaryOperator 'int' prefix '!'
   165  	// `-ParenExpr 'int'
   166  	//   `-BinaryOperator 'int' '='
   167  	//     |-DeclRefExpr 'int' lvalue Var 0x3329b60 'y' 'int'
   168  	//     `-ImplicitCastExpr 'int' <LValueToRValue>
   169  	//       `-DeclRefExpr 'int' lvalue Var 0x3329ab8 'p' 'int'
   170  	if par, ok := e.(*goast.ParenExpr); ok {
   171  		if bi, ok := par.X.(*goast.BinaryExpr); ok {
   172  			if bi.Op == token.ASSIGN { // =
   173  				preStmts = append(preStmts, &goast.ExprStmt{
   174  					X: bi,
   175  				})
   176  				e = bi.X
   177  			}
   178  		}
   179  	}
   180  
   181  	// null in C is zero
   182  	if eType == types.NullPointer {
   183  		e = &goast.BasicLit{
   184  			Kind:  token.INT,
   185  			Value: "0",
   186  		}
   187  		eType = "int"
   188  	}
   189  
   190  	if eType == "bool" {
   191  		return util.NewUnaryExpr(e, token.NOT), "bool", preStmts, postStmts, nil
   192  	}
   193  
   194  	if strings.HasSuffix(eType, "*") {
   195  		// `!pointer` has to be converted to `pointer == nil`
   196  		return &goast.BinaryExpr{
   197  			X:  e,
   198  			Op: token.EQL,
   199  			Y:  util.NewIdent("nil"),
   200  		}, "bool", preStmts, postStmts, nil
   201  	}
   202  
   203  	t, err := types.ResolveType(p, eType)
   204  	p.AddMessage(p.GenerateWarningMessage(err, n))
   205  
   206  	if t == "[]byte" {
   207  		return util.NewUnaryExpr(
   208  			util.NewCallExpr("noarch.CStringIsNull", e), token.NOT,
   209  		), "bool", preStmts, postStmts, nil
   210  	}
   211  
   212  	// only if added "stdbool.h"
   213  	if p.IncludeHeaderIsExists("stdbool.h") {
   214  		if t == "_Bool" {
   215  			t = "int32"
   216  			e = util.NewCallExpr("int32", e)
   217  		}
   218  	}
   219  
   220  	p.AddImport("github.com/Konstantin8105/c4go/noarch")
   221  
   222  	eType = "bool"
   223  
   224  	return util.NewCallExpr("noarch.Not", e),
   225  		eType, preStmts, postStmts, nil
   226  }
   227  
   228  // transpileUnaryOperatorAmpersant - operator ampersant &
   229  // Example of AST:
   230  //
   231  // UnaryOperator 'int (*)[5]' prefix '&'
   232  // `-DeclRefExpr 'int [5]' lvalue Var 0x2d0fb20 'arr' 'int [5]'
   233  //
   234  // UnaryOperator 'char **' prefix '&'
   235  // `-DeclRefExpr 'char *' lvalue Var 0x39b95f0 'line' 'char *'
   236  //
   237  // UnaryOperator 'float *' prefix '&'
   238  // `-DeclRefExpr 'float' lvalue Var 0x409e2a0 't' 'float'
   239  func transpileUnaryOperatorAmpersant(n *ast.UnaryOperator, p *program.Program) (
   240  	expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   241  	defer func() {
   242  		if err != nil {
   243  			err = fmt.Errorf("cannot transpileUnaryOperatorAmpersant : err = %v", err)
   244  		}
   245  	}()
   246  
   247  	expr, eType, preStmts, postStmts, err = transpileToExpr(n.Children()[0], p, false)
   248  	if err != nil {
   249  		return
   250  	}
   251  	if expr == nil {
   252  		err = fmt.Errorf("expr is nil")
   253  		return
   254  	}
   255  
   256  	if util.IsFunction(eType) {
   257  		return
   258  	}
   259  
   260  	if util.IsLastArray(eType) {
   261  		// In : eType = 'int [5]'
   262  		// Out: eType = 'int *'
   263  		f := strings.Index(eType, "[")
   264  		e := strings.Index(eType, "]")
   265  		if e == len(eType)-1 {
   266  			eType = eType[:f] + "*"
   267  		} else {
   268  			eType = eType[:f] + "*" + eType[e+1:]
   269  		}
   270  		return
   271  	}
   272  
   273  	if ind, ok := expr.(*goast.IndexExpr); ok {
   274  		// from :
   275  		//
   276  		// 0  *ast.IndexExpr {
   277  		// 1  .  X: *ast.Ident {
   278  		// 3  .  .  Name: "b"
   279  		// 4  .  }
   280  		// 6  .  Index: *ast.BasicLit { ... }
   281  		// 12  }
   282  		//
   283  		// to:
   284  		//
   285  		// 88  0: *ast.SliceExpr {
   286  		// 89  .  X: *ast.Ident {
   287  		// 91  .  .  Name: "b"
   288  		// 93  .  }
   289  		// 95  .  Low: *ast.BasicLit { ... }
   290  		// 99  .  }
   291  		// 102  }
   292  		expr = &goast.SliceExpr{
   293  			X:      ind.X,
   294  			Low:    ind.Index,
   295  			Slice3: false,
   296  		}
   297  		eType = n.Type
   298  		return
   299  	}
   300  
   301  	// In : eType = 'int'
   302  	// Out: eType = 'int *'
   303  	// FIXME: This will need to use a real slice to reference the original
   304  	// value.
   305  	resolvedType, err := types.ResolveType(p, eType)
   306  	if err != nil {
   307  		p.AddMessage(p.GenerateWarningMessage(err, n))
   308  		return
   309  	}
   310  
   311  	// We now have a pointer to the original type.
   312  	eType += " *"
   313  
   314  	p.AddImport("unsafe")
   315  
   316  	// UnaryOperator 'float *' prefix '&'
   317  	// `-DeclRefExpr 'float' lvalue Var 0x409e2a0 't' 'float'
   318  	if e, ok := ConvertValueToPointer(n.Children(), p); ok {
   319  		expr = e
   320  		return
   321  	}
   322  
   323  	expr = CreateSliceFromReference(resolvedType, expr)
   324  
   325  	return
   326  }
   327  
   328  // pointerParts - separate to pointer and value.
   329  //   - change type for all nodes to `int`
   330  //
   331  // BinaryOperator <col:13, col:57> 'int *' '-'
   332  // |-BinaryOperator <col:13, col:40> 'int *' '+'
   333  // | |-BinaryOperator <col:13, col:32> 'int *' '+'
   334  // | | |-BinaryOperator <col:13, col:21> 'int *' '+'
   335  // | | | |-BinaryOperator <col:13, col:17> 'int' '+'
   336  // | | | | |-IntegerLiteral <col:13> 'int' 1
   337  // | | | | `-IntegerLiteral <col:17> 'int' 0
   338  // | | | `-ImplicitCastExpr <col:21> 'int *' <LValueToRValue>
   339  // | | |   `-DeclRefExpr <col:21> 'int *' lvalue Var 0x29a91a8 'i5' 'int *'
   340  // | | `-BinaryOperator <col:26, col:32> 'long' '*'
   341  // | |   |-ImplicitCastExpr <col:26> 'long' <IntegralCast>
   342  // | |   | `-IntegerLiteral <col:26> 'int' 5
   343  // | |   `-CallExpr <col:28, col:32> 'long'
   344  // | |     `-ImplicitCastExpr <col:28> 'long (*)()' <FunctionToPointerDecay>
   345  // | |       `-DeclRefExpr <col:28> 'long ()' Function 0x29a8470 'get' 'long ()'
   346  // | `-CallExpr <col:36, col:40> 'long'
   347  // |   `-ImplicitCastExpr <col:36> 'long (*)()' <FunctionToPointerDecay>
   348  // |     `-DeclRefExpr <col:36> 'long ()' Function 0x29a8470 'get' 'long ()'
   349  // `-BinaryOperator <col:44, col:57> 'long' '*'
   350  //
   351  //	|-ImplicitCastExpr <col:44, col:51> 'long' <IntegralCast>
   352  //	| `-ParenExpr <col:44, col:51> 'int'
   353  //	|   `-BinaryOperator <col:45, col:50> 'int' '+'
   354  //	|     |-IntegerLiteral <col:45> 'int' 12
   355  //	|     `-IntegerLiteral <col:50> 'int' 3
   356  //	`-CallExpr <col:53, col:57> 'long'
   357  //	  `-ImplicitCastExpr <col:53> 'long (*)()' <FunctionToPointerDecay>
   358  //	    `-DeclRefExpr <col:53> 'long ()' Function 0x29a8470 'get' 'long ()'
   359  //
   360  // ParenExpr <col:25, col:31> 'char *'
   361  // `-UnaryOperator <col:26, col:29> 'char *' postfix '++'
   362  //
   363  //	`-DeclRefExpr <col:26> 'char *' lvalue Var 0x3c05ae8 'pos' 'char *'
   364  //
   365  // BinaryOperator 0x128d3b8 <col:8, col:28> 'char *' '+'
   366  // |-ImplicitCastExpr 0x128d3a0 <col:8> 'char *' <ArrayToPointerDecay>
   367  // | `-DeclRefExpr 0x128d2d0 <col:8> 'char [262144]' lvalue Var 0x128b730 'hynums' 'char [262144]'
   368  // `-ParenExpr 0x128d380 <col:17, col:28> 'long'
   369  //
   370  //	`-BinaryOperator 0x128d360 <col:18, col:22> 'long' '-'
   371  //	  |-ImplicitCastExpr 0x128d330 <col:18> 'char *' <LValueToRValue>
   372  //	  | `-DeclRefExpr 0x128d2f0 <col:18> 'char *' lvalue Var 0x128bc80 'p' 'char *'
   373  //	  `-ImplicitCastExpr 0x128d348 <col:22> 'char *' <ArrayToPointerDecay>
   374  //	    `-DeclRefExpr 0x128d310 <col:22> 'char [262144]' lvalue Var 0x128b610 'hypats' 'char [262144]'
   375  func pointerParts(node *ast.Node, p *program.Program) (
   376  	pnt ast.Node, value ast.Node, back func(), undefineIndex bool, err error) {
   377  	defer func() {
   378  		if err != nil {
   379  			err = fmt.Errorf("cannot pointerParts: err = %v", err)
   380  		}
   381  	}()
   382  
   383  	var counter int
   384  
   385  	var lastNode *ast.Node
   386  
   387  	// replacer zero
   388  	zero := &ast.IntegerLiteral{Type: "int", Value: "0"}
   389  
   390  	var baseTypes []*string
   391  	var searcher func(*ast.Node) bool
   392  	replacer := func(node *ast.Node) {
   393  		pnt = *node
   394  		lastNode = node
   395  		*node = zero
   396  		counter++
   397  	}
   398  	searcher = func(node *ast.Node) (modify bool) {
   399  		// save types of all nodes
   400  		t, ok := ast.GetTypeIfExist(*node)
   401  		if !ok {
   402  			panic(fmt.Errorf("not support parent type %T in pointer seaching", node))
   403  		}
   404  		baseTypes = append(baseTypes, t)
   405  
   406  		*t = util.CleanCType(*t)
   407  
   408  		// typedef type
   409  		var td string = util.CleanCType(*t)
   410  		for {
   411  			if te, ok := p.TypedefType[td]; ok {
   412  				td = util.CleanCType(te)
   413  				continue
   414  			}
   415  			break
   416  		}
   417  		// find
   418  		if types.IsCPointer(*t, p) || types.IsCArray(*t, p) ||
   419  			types.IsCPointer(td, p) || types.IsCArray(td, p) {
   420  			switch (*node).(type) {
   421  			case *ast.BinaryOperator,
   422  				*ast.ImplicitCastExpr,
   423  				*ast.ParenExpr:
   424  				undefineIndex = true // is index probably negative
   425  				// go deeper
   426  			default:
   427  				return true
   428  			}
   429  		} else {
   430  			// type is not pointer
   431  			switch (*node).(type) {
   432  			case *ast.CallExpr,
   433  				*ast.ArraySubscriptExpr,
   434  				*ast.MemberExpr,
   435  				*ast.UnaryExprOrTypeTraitExpr, // ignore sizeof
   436  				*ast.CStyleCastExpr:
   437  				undefineIndex = true // is index probably negative
   438  				return
   439  			}
   440  		}
   441  		switch (*node).(type) {
   442  		case *ast.UnaryOperator:
   443  			baseTypes = baseTypes[:len(baseTypes)-1]
   444  			return
   445  		}
   446  		for i := range (*node).Children() {
   447  			if searcher(&((*node).Children()[i])) {
   448  				replacer(&((*node).Children()[i]))
   449  			}
   450  		}
   451  		return false
   452  	}
   453  	if searcher(node) {
   454  		pnt = *node
   455  		lastNode = node
   456  		*node = zero
   457  		counter++
   458  	}
   459  
   460  	if counter != 1 {
   461  		err = fmt.Errorf("counter is not 1: %d", counter)
   462  		return
   463  	}
   464  	if pnt == nil {
   465  		err = fmt.Errorf("pointer is nil")
   466  		return
   467  	}
   468  
   469  	copyTypes := make([]string, len(baseTypes))
   470  	for i := range baseTypes {
   471  		copyTypes[i] = *(baseTypes[i])
   472  	}
   473  	back = func() {
   474  		// return back types
   475  		for i := range baseTypes {
   476  			*(baseTypes[i]) = copyTypes[i]
   477  		}
   478  		// return back node
   479  		*lastNode = pnt
   480  	}
   481  
   482  	// replace all types to `int`
   483  	for i := range baseTypes {
   484  		*baseTypes[i] = `int`
   485  	}
   486  
   487  	value = *node
   488  
   489  	return
   490  }
   491  
   492  // transpilePointerArith - transpile pointer aripthmetic
   493  // Example of using:
   494  // *(t + 1) = ...
   495  func transpilePointerArith(n *ast.UnaryOperator, p *program.Program) (
   496  	expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   497  	defer func() {
   498  		if err != nil {
   499  			err = fmt.Errorf("cannot transpilePointerArith: err = %v", err)
   500  		}
   501  	}()
   502  
   503  	if n.Operator != "*" {
   504  		err = fmt.Errorf("not valid operator : %s", n.Operator)
   505  		return
   506  	}
   507  
   508  	var pnt, value ast.Node
   509  	var back func()
   510  	var undefineIndex bool
   511  	pnt, value, back, undefineIndex, err = pointerParts(&(n.Children()[0]), p)
   512  	if err != nil {
   513  		return
   514  	}
   515  	_ = undefineIndex
   516  
   517  	e, eType, newPre, newPost, err := atomicOperation(value, p)
   518  	if err != nil {
   519  		return
   520  	}
   521  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   522  	eType = n.Type
   523  
   524  	// return all types
   525  	back()
   526  
   527  	arr, arrType, newPre, newPost, err := atomicOperation(pnt, p)
   528  	if err != nil {
   529  		return
   530  	}
   531  	_ = arrType
   532  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   533  
   534  	switch v := pnt.(type) {
   535  	case *ast.MemberExpr:
   536  		return &goast.IndexExpr{
   537  			X:     arr,
   538  			Index: e,
   539  		}, eType, preStmts, postStmts, err
   540  
   541  	case *ast.DeclRefExpr:
   542  		return &goast.IndexExpr{
   543  			X:     util.NewIdent(v.Name),
   544  			Index: e,
   545  		}, eType, preStmts, postStmts, err
   546  
   547  	case *ast.CStyleCastExpr, *ast.VAArgExpr, *ast.CallExpr, *ast.ArraySubscriptExpr:
   548  		return &goast.IndexExpr{
   549  			X: &goast.ParenExpr{
   550  				X:      arr,
   551  				Lparen: 1,
   552  			},
   553  			Index: e,
   554  		}, eType, preStmts, postStmts, err
   555  
   556  	case *ast.UnaryOperator:
   557  		if memberName, ok := getMemberName(n.Children()[0]); ok {
   558  			return &goast.IndexExpr{
   559  				X: &goast.SelectorExpr{
   560  					X:   arr,
   561  					Sel: util.NewIdent(memberName),
   562  				},
   563  				Index: &goast.BasicLit{
   564  					Kind:  token.INT,
   565  					Value: "0",
   566  				},
   567  			}, eType, preStmts, postStmts, err
   568  		}
   569  		return &goast.IndexExpr{
   570  			X: &goast.ParenExpr{
   571  				Lparen: 1,
   572  				X:      arr,
   573  			},
   574  			Index: e,
   575  		}, eType, preStmts, postStmts, err
   576  
   577  	}
   578  	return nil, "", nil, nil, fmt.Errorf("cannot found : %#v", pnt)
   579  }
   580  
   581  func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program) (
   582  	_ goast.Expr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   583  	defer func() {
   584  		if err != nil {
   585  			err = fmt.Errorf("cannot transpile UnaryOperator: err = %v", err)
   586  			p.AddMessage(p.GenerateWarningMessage(err, n))
   587  		}
   588  	}()
   589  
   590  	operator, err := getTokenForOperator(n.Operator)
   591  	if err != nil {
   592  		err = nil
   593  		return transpileToExpr(n.Children()[0], p, true)
   594  	}
   595  
   596  	switch operator {
   597  	case token.MUL: // *
   598  		// Prefix "*" is not a multiplication.
   599  		// Prefix "*" used for pointer ariphmetic
   600  		// Example of using:
   601  		// *(t + 1) = ...
   602  		return transpilePointerArith(n, p)
   603  	case token.INC, token.DEC: // ++, --
   604  		return transpileUnaryOperatorInc(n, p, operator)
   605  	case token.NOT: // !
   606  		return transpileUnaryOperatorNot(n, p)
   607  	case token.AND: // &
   608  		return transpileUnaryOperatorAmpersant(n, p)
   609  	}
   610  
   611  	// Example:
   612  	// UnaryOperator 'unsigned int' prefix '-'
   613  	// `-IntegerLiteral 'unsigned int' 1
   614  	if il, ok := n.Children()[0].(*ast.IntegerLiteral); ok && types.IsCUnsignedType(n.Type) {
   615  		var value float64
   616  		value, err = strconv.ParseFloat(il.Value, 64)
   617  		if err == nil && value > 0 {
   618  			var resolveType string
   619  			resolveType, err = types.ResolveType(p, n.Type)
   620  			if err == nil && resolveType != "" {
   621  				return util.ConvertToUnsigned(goast.NewIdent(fmt.Sprintf("-%s", il.Value)), resolveType),
   622  					n.Type, preStmts, postStmts, nil
   623  			}
   624  		}
   625  		err = nil
   626  	}
   627  
   628  	// Example:
   629  	// UnaryOperator 'int' prefix '-'
   630  	// `-ImplicitCastExpr 'int' <LValueToRValue>
   631  	//   `-DeclRefExpr 'int' lvalue Var 0x3b42898 'c' 'int'
   632  
   633  	// Otherwise handle like a unary operator.
   634  	e, eType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false)
   635  	if err != nil {
   636  		return nil, "", nil, nil, err
   637  	}
   638  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   639  
   640  	return util.NewUnaryExpr(e, operator), eType, preStmts, postStmts, nil
   641  }
   642  
   643  func transpileUnaryExprOrTypeTraitExpr(n *ast.UnaryExprOrTypeTraitExpr, p *program.Program) (
   644  	*goast.BasicLit, string, []goast.Stmt, []goast.Stmt, error) {
   645  	t := n.Type2
   646  
   647  	// It will have children if the sizeof() is referencing a variable.
   648  	// Fortunately clang already has the type in the AST for us.
   649  	if len(n.Children()) > 0 {
   650  		if typ, ok := ast.GetTypeIfExist(n.Children()[0]); ok {
   651  			t = *typ
   652  		} else {
   653  			panic(fmt.Sprintf("cannot find first child from: %#v", n.Children()[0]))
   654  		}
   655  	}
   656  
   657  	sizeInBytes, err := types.SizeOf(p, t)
   658  	if err != nil {
   659  		p.AddMessage(p.GenerateWarningMessage(err, n))
   660  		err = nil // ignore error
   661  	}
   662  	if sizeInBytes == 0 {
   663  		p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("zero sizeof for '%s'", t), n))
   664  	}
   665  
   666  	return util.NewIntLit(sizeInBytes), n.Type1, nil, nil, nil
   667  }
   668  
   669  func transpileStmtExpr(n *ast.StmtExpr, p *program.Program) (
   670  	*goast.CallExpr, string, []goast.Stmt, []goast.Stmt, error) {
   671  	returnType, err := types.ResolveType(p, n.Type)
   672  	if err != nil {
   673  		return nil, "", nil, nil, err
   674  	}
   675  
   676  	body, pre, post, err := transpileCompoundStmt(n.Children()[0].(*ast.CompoundStmt), p)
   677  	if err != nil {
   678  		return nil, "", pre, post, err
   679  	}
   680  
   681  	// The body of the StmtExpr is always a CompoundStmt. However, the last
   682  	// statement needs to be transformed into an explicit return statement.
   683  	if e, ok := body.List[len(body.List)-1].(*goast.ExprStmt); ok {
   684  		body.List[len(body.List)-1] = &goast.ReturnStmt{
   685  			Results: []goast.Expr{e.X},
   686  		}
   687  	}
   688  
   689  	return util.NewFuncClosure(returnType, body.List...), n.Type, pre, post, nil
   690  }