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

     1  // This file contains functions for transpiling binary operator expressions.
     2  
     3  package transpiler
     4  
     5  import (
     6  	"fmt"
     7  	goast "go/ast"
     8  	"go/token"
     9  	"strings"
    10  
    11  	"github.com/Konstantin8105/c4go/ast"
    12  	"github.com/Konstantin8105/c4go/program"
    13  	"github.com/Konstantin8105/c4go/types"
    14  	"github.com/Konstantin8105/c4go/util"
    15  )
    16  
    17  // Comma problem. Example:
    18  // for (int i=0,j=0;i+=1,j<5;i++,j++){...}
    19  // For solving - we have to separate the
    20  // binary operator "," to 2 parts:
    21  // part 1(pre ): left part  - typically one or more some expressions
    22  // part 2(stmt): right part - always only one expression, with or without
    23  //
    24  //	logical operators like "==", "!=", ...
    25  func transpileBinaryOperatorComma(n *ast.BinaryOperator, p *program.Program) (
    26  	stmt goast.Stmt, preStmts []goast.Stmt, err error) {
    27  	defer func() {
    28  		if err != nil {
    29  			err = fmt.Errorf("cannot transpile operator comma : err = %v", err)
    30  			p.AddMessage(p.GenerateWarningMessage(err, n))
    31  		}
    32  	}()
    33  
    34  	left, err := transpileToStmts(n.Children()[0], p)
    35  	if err != nil {
    36  		return nil, nil, err
    37  	}
    38  
    39  	right, err := transpileToStmts(n.Children()[1], p)
    40  	if err != nil {
    41  		return nil, nil, err
    42  	}
    43  
    44  	if left == nil || right == nil {
    45  		return nil, nil,
    46  			fmt.Errorf("cannot transpile binary operator comma: right = %v , left = %v",
    47  				right, left)
    48  	}
    49  
    50  	preStmts = append(preStmts, left...)
    51  	preStmts = append(preStmts, right...)
    52  
    53  	if len(preStmts) >= 2 {
    54  		return preStmts[len(preStmts)-1], preStmts[:len(preStmts)-1], nil
    55  	}
    56  
    57  	if len(preStmts) == 1 {
    58  		return preStmts[0], nil, nil
    59  	}
    60  	return nil, nil, nil
    61  }
    62  
    63  func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsStmt bool) (
    64  	expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
    65  	defer func() {
    66  		if err != nil {
    67  			err = fmt.Errorf(
    68  				"cannot transpile BinaryOperator with type '%s' :"+
    69  					" result type = {%s}. Error: %v", n.Type, eType, err)
    70  			p.AddMessage(p.GenerateWarningMessage(err, n))
    71  		}
    72  	}()
    73  
    74  	operator := getTokenForOperatorNoError(n.Operator)
    75  	n.Type = util.GenerateCorrectType(n.Type)
    76  	n.Type2 = util.GenerateCorrectType(n.Type2)
    77  
    78  	defer func() {
    79  		if err != nil {
    80  			err = fmt.Errorf("operator is `%v`. %v", operator, err)
    81  		}
    82  	}()
    83  
    84  	// Char overflow
    85  	// BinaryOperator  'int' '!='
    86  	// |-ImplicitCastExpr 'int' <IntegralCast>
    87  	// | `-ImplicitCastExpr 'char' <LValueToRValue>
    88  	// |   `-...
    89  	// `-ParenExpr 'int'
    90  	//   `-UnaryOperator 'int' prefix '-'
    91  	//     `-IntegerLiteral 'int' 1
    92  	if n.Operator == "!=" {
    93  		var leftOk bool
    94  		if l0, ok := n.ChildNodes[0].(*ast.ImplicitCastExpr); ok && l0.Type == "int" {
    95  			if len(l0.ChildNodes) > 0 {
    96  				if l1, ok := l0.ChildNodes[0].(*ast.ImplicitCastExpr); ok && l1.Type == "char" {
    97  					leftOk = true
    98  				}
    99  			}
   100  		}
   101  		if leftOk {
   102  			if r0, ok := n.ChildNodes[1].(*ast.ParenExpr); ok && r0.Type == "int" {
   103  				if len(r0.ChildNodes) > 0 {
   104  					if r1, ok := r0.ChildNodes[0].(*ast.UnaryOperator); ok && r1.IsPrefix && r1.Operator == "-" {
   105  						if r2, ok := r1.ChildNodes[0].(*ast.IntegerLiteral); ok && r2.Type == "int" {
   106  							r0.ChildNodes[0] = &ast.BinaryOperator{
   107  								Type:     "int",
   108  								Type2:    "int",
   109  								Operator: "+",
   110  								ChildNodes: []ast.Node{
   111  									r1,
   112  									&ast.IntegerLiteral{
   113  										Type:  "int",
   114  										Value: "256",
   115  									},
   116  								},
   117  							}
   118  						}
   119  					}
   120  				}
   121  			}
   122  		}
   123  	}
   124  
   125  	// Example of C code
   126  	// a = b = 1
   127  	// // Operation equal transpile from right to left
   128  	// Solving:
   129  	// b = 1, a = b
   130  	// // Operation comma transpile from left to right
   131  	// If we have for example:
   132  	// a = b = c = 1
   133  	// then solution is:
   134  	// c = 1, b = c, a = b
   135  	// |-----------|
   136  	// this part, created in according to
   137  	// recursive working
   138  	// Example of AST tree for problem:
   139  	// |-BinaryOperator 0x2f17870 <line:13:2, col:10> 'int' '='
   140  	// | |-DeclRefExpr 0x2f177d8 <col:2> 'int' lvalue Var 0x2f176d8 'x' 'int'
   141  	// | `-BinaryOperator 0x2f17848 <col:6, col:10> 'int' '='
   142  	// |   |-DeclRefExpr 0x2f17800 <col:6> 'int' lvalue Var 0x2f17748 'y' 'int'
   143  	// |   `-IntegerLiteral 0x2f17828 <col:10> 'int' 1
   144  	//
   145  	// Example of AST tree for solution:
   146  	// |-BinaryOperator 0x368e8d8 <line:13:2, col:13> 'int' ','
   147  	// | |-BinaryOperator 0x368e820 <col:2, col:6> 'int' '='
   148  	// | | |-DeclRefExpr 0x368e7d8 <col:2> 'int' lvalue Var 0x368e748 'y' 'int'
   149  	// | | `-IntegerLiteral 0x368e800 <col:6> 'int' 1
   150  	// | `-BinaryOperator 0x368e8b0 <col:9, col:13> 'int' '='
   151  	// |   |-DeclRefExpr 0x368e848 <col:9> 'int' lvalue Var 0x368e6d8 'x' 'int'
   152  	// |   `-ImplicitCastExpr 0x368e898 <col:13> 'int' <LValueToRValue>
   153  	// |     `-DeclRefExpr 0x368e870 <col:13> 'int' lvalue Var 0x368e748 'y' 'int'
   154  	//
   155  	// Example
   156  	// BinaryOperator 'const char *' '='
   157  	// |-...
   158  	// `-ImplicitCastExpr 'const char *' <BitCast>
   159  	//   `-BinaryOperator 'char *' '='
   160  	//     |-...
   161  	//     `-...
   162  	if getTokenForOperatorNoError(n.Operator) == token.ASSIGN {
   163  		child := n.Children()[1]
   164  		if impl, ok := child.(*ast.ImplicitCastExpr); ok {
   165  			child = impl.Children()[0]
   166  		}
   167  		switch c := child.(type) {
   168  		case *ast.BinaryOperator:
   169  			if getTokenForOperatorNoError(c.Operator) == token.ASSIGN {
   170  				bSecond := ast.BinaryOperator{
   171  					Type:     c.Type,
   172  					Operator: "=",
   173  				}
   174  				bSecond.AddChild(n.Children()[0])
   175  
   176  				var impl ast.ImplicitCastExpr
   177  				impl.Type = c.Type
   178  				impl.Kind = "LValueToRValue"
   179  				impl.AddChild(c.Children()[0])
   180  				bSecond.AddChild(&impl)
   181  
   182  				var bComma ast.BinaryOperator
   183  				bComma.Operator = ","
   184  				bComma.Type = c.Type
   185  				bComma.AddChild(c)
   186  				bComma.AddChild(&bSecond)
   187  
   188  				// exprIsStmt now changes to false to stop any AST children from
   189  				// not being safely wrapped in a closure.
   190  				return transpileBinaryOperator(&bComma, p, false)
   191  			}
   192  		}
   193  	}
   194  
   195  	// Example of C code
   196  	// a = 1, b = a
   197  	// Solving
   198  	// a = 1; // preStmts
   199  	// b = a; // n
   200  	// Example of AST tree for problem:
   201  	// |-BinaryOperator 0x368e8d8 <line:13:2, col:13> 'int' ','
   202  	// | |-BinaryOperator 0x368e820 <col:2, col:6> 'int' '='
   203  	// | | |-DeclRefExpr 0x368e7d8 <col:2> 'int' lvalue Var 0x368e748 'y' 'int'
   204  	// | | `-IntegerLiteral 0x368e800 <col:6> 'int' 1
   205  	// | `-BinaryOperator 0x368e8b0 <col:9, col:13> 'int' '='
   206  	// |   |-DeclRefExpr 0x368e848 <col:9> 'int' lvalue Var 0x368e6d8 'x' 'int'
   207  	// |   `-ImplicitCastExpr 0x368e898 <col:13> 'int' <LValueToRValue>
   208  	// |     `-DeclRefExpr 0x368e870 <col:13> 'int' lvalue Var 0x368e748 'y' 'int'
   209  	//
   210  	// Example of AST tree for solution:
   211  	// |-BinaryOperator 0x21a7820 <line:13:2, col:6> 'int' '='
   212  	// | |-DeclRefExpr 0x21a77d8 <col:2> 'int' lvalue Var 0x21a7748 'y' 'int'
   213  	// | `-IntegerLiteral 0x21a7800 <col:6> 'int' 1
   214  	// |-BinaryOperator 0x21a78b0 <line:14:2, col:6> 'int' '='
   215  	// | |-DeclRefExpr 0x21a7848 <col:2> 'int' lvalue Var 0x21a76d8 'x' 'int'
   216  	// | `-ImplicitCastExpr 0x21a7898 <col:6> 'int' <LValueToRValue>
   217  	// |   `-DeclRefExpr 0x21a7870 <col:6> 'int' lvalue Var 0x21a7748 'y' 'int'
   218  	if getTokenForOperatorNoError(n.Operator) == token.COMMA {
   219  		stmts, _, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false)
   220  		if err != nil {
   221  			err = fmt.Errorf("cannot transpile expr `token.COMMA` child 0. %v", err)
   222  			return nil, "unknown50", nil, nil, err
   223  		}
   224  		preStmts = append(preStmts, newPre...)
   225  		preStmts = append(preStmts, util.NewExprStmt(stmts))
   226  		preStmts = append(preStmts, newPost...)
   227  
   228  		var st string
   229  		stmts, st, newPre, newPost, err = transpileToExpr(n.Children()[1], p, false)
   230  		if err != nil {
   231  			err = fmt.Errorf("cannot transpile expr `token.COMMA` child 1. %v", err)
   232  			return nil, "unknown51", nil, nil, err
   233  		}
   234  		// Theoretically , we don't have any preStmts or postStmts
   235  		// from n.Children()[1]
   236  		if len(newPre) > 0 || len(newPost) > 0 {
   237  			p.AddMessage(p.GenerateWarningMessage(
   238  				fmt.Errorf("not support length pre or post stmts: {%d,%d}",
   239  					len(newPre), len(newPost)), n))
   240  		}
   241  		return stmts, st, preStmts, postStmts, nil
   242  	}
   243  
   244  	// pointer arithmetic
   245  	if types.IsPointer(n.Type, p) {
   246  		if operator == token.ADD || // +
   247  			false {
   248  
   249  			// not acceptable binaryOperator with operator `-`
   250  			haveSub := false
   251  			{
   252  				var check func(ast.Node)
   253  				check = func(node ast.Node) {
   254  					if node == nil {
   255  						return
   256  					}
   257  					if bin, ok := node.(*ast.BinaryOperator); ok && bin.Operator == "-" {
   258  						haveSub = true
   259  					}
   260  					for i := range node.Children() {
   261  						check(node.Children()[i])
   262  					}
   263  				}
   264  				check(n)
   265  			}
   266  
   267  			if !haveSub {
   268  
   269  				fakeUnary := &ast.UnaryOperator{
   270  					Type:     n.Type,
   271  					Operator: "*",
   272  					ChildNodes: []ast.Node{
   273  						n,
   274  					},
   275  				}
   276  
   277  				var newPre, newPost []goast.Stmt
   278  				expr, eType, newPre, newPost, err =
   279  					transpilePointerArith(fakeUnary, p)
   280  				eType = n.Type
   281  
   282  				if err != nil {
   283  					return
   284  				}
   285  				if expr == nil {
   286  					return nil, "", nil, nil, fmt.Errorf("expr is nil")
   287  				}
   288  				preStmts, postStmts =
   289  					combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   290  
   291  				if ind, ok := expr.(*goast.IndexExpr); ok {
   292  					expr = &goast.SliceExpr{
   293  						X:      ind.X,
   294  						Low:    ind.Index,
   295  						Slice3: false,
   296  					}
   297  				}
   298  
   299  				return
   300  			}
   301  		}
   302  	}
   303  
   304  	left, leftType, newPre, newPost, err := atomicOperation(n.Children()[0], p)
   305  	if err != nil {
   306  		err = fmt.Errorf("cannot atomic for left part. %v", err)
   307  		return nil, "unknown52", nil, nil, err
   308  	}
   309  
   310  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   311  
   312  	right, rightType, newPre, newPost, err := atomicOperation(n.Children()[1], p)
   313  	if err != nil {
   314  		err = fmt.Errorf("cannot atomic for right part. %v", err)
   315  		return nil, "unknown53", nil, nil, err
   316  	}
   317  
   318  	if types.IsPointer(leftType, p) && types.IsPointer(rightType, p) {
   319  		switch operator {
   320  		case token.SUB: // -
   321  			p.AddImport("unsafe")
   322  			var sizeof int
   323  			sizeof, err = types.SizeOf(p, types.GetBaseType(leftType))
   324  			if err != nil {
   325  				return nil, "PointerOperation_unknown01", nil, nil, err
   326  			}
   327  			var e goast.Expr
   328  			var newPost []goast.Stmt
   329  			e, newPost, err = SubTwoPnts(p, left, leftType, right, rightType, sizeof)
   330  			if err != nil {
   331  				return nil, "PointerOperation_unknown02", nil, nil, err
   332  			}
   333  			postStmts = append(postStmts, newPost...)
   334  
   335  			expr, err = types.CastExpr(p, e, "long long", n.Type)
   336  			if err != nil {
   337  				return nil, "PointerOperation_unknown03", nil, nil, err
   338  			}
   339  			eType = n.Type
   340  			return
   341  
   342  		case token.GTR, token.GEQ, // >  >=
   343  			token.LOR,            // ||
   344  			token.LAND,           // &&
   345  			token.LSS, token.LEQ, // <  <=
   346  			token.EQL, token.NEQ: // == !=
   347  
   348  			// IfStmt 0x2369a68 <line:210:3, line:211:11>
   349  			// |-BinaryOperator 0x2369a00 <line:210:7, col:21> 'int' '=='
   350  			// | |-ImplicitCastExpr 0x23699d0 <col:7, col:16> 'struct font *' <LValueToRValue>
   351  			// | | `-ArraySubscriptExpr 0x2369990 <col:7, col:16> 'struct font *' lvalue
   352  			// | |   |-ImplicitCastExpr 0x2369960 <col:7> 'struct font **' <ArrayToPointerDecay>
   353  			// | |   | `-DeclRefExpr 0x2369920 <col:7> 'struct font *[32]' lvalue Var 0x235fbe8 'fn_font' 'struct font *[32]'
   354  			// | |   `-ImplicitCastExpr 0x2369978 <col:15> 'int' <LValueToRValue>
   355  			// | |     `-DeclRefExpr 0x2369940 <col:15> 'int' lvalue Var 0x2369790 'i' 'int'
   356  			// | `-ImplicitCastExpr 0x23699e8 <col:21> 'struct font *' <LValueToRValue>
   357  			// |   `-DeclRefExpr 0x23699b0 <col:21> 'struct font *' lvalue ParmVar 0x2369638 'fn' 'struct font *'
   358  			// `-ReturnStmt 0x2369a58 <line:211:4, col:11>
   359  			//   `-ImplicitCastExpr 0x2369a40 <col:11> 'int' <LValueToRValue>
   360  			//     `-DeclRefExpr 0x2369a20 <col:11> 'int' lvalue Var 0x2369790 'i' 'int'
   361  
   362  			var sizeof int
   363  			baseType := types.GetBaseType(leftType)
   364  			sizeof, err = types.SizeOf(p, baseType)
   365  			if err != nil {
   366  				err = fmt.Errorf("{'%s' %v '%s'}. sizeof = %d for baseType = '%s'. %v",
   367  					leftType, operator, rightType, sizeof, baseType, err)
   368  				return nil, "PointerOperation_unknown04", nil, nil, err
   369  			}
   370  			var e goast.Expr
   371  			var newPost []goast.Stmt
   372  			e, newPost, err = PntCmpPnt(
   373  				p,
   374  				left, leftType,
   375  				right, rightType,
   376  				sizeof, operator,
   377  			)
   378  			if err != nil {
   379  				err = fmt.Errorf("{'%s' %v '%s'}. for base type: `%s`. %v",
   380  					leftType, operator, rightType, baseType, err)
   381  				return nil, "PointerOperation_unknown05", nil, nil, err
   382  			}
   383  			postStmts = append(postStmts, newPost...)
   384  			expr = e
   385  			eType = "bool"
   386  
   387  			return
   388  
   389  		case token.ASSIGN: // =
   390  			// ignore
   391  
   392  		default:
   393  			err = fmt.Errorf("not implemented pointer operation: %v", operator)
   394  			return
   395  		}
   396  	}
   397  
   398  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   399  
   400  	returnType := types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType)
   401  
   402  	if operator == token.LAND || operator == token.LOR { // && ||
   403  		left, err = types.CastExpr(p, left, leftType, "bool")
   404  		if err != nil {
   405  			p.AddMessage(p.GenerateWarningMessage(err, n))
   406  			// ignore error
   407  			left = util.NewNil()
   408  			err = nil
   409  		}
   410  
   411  		right, err = types.CastExpr(p, right, rightType, "bool")
   412  		if err != nil {
   413  			p.AddMessage(p.GenerateWarningMessage(err, n))
   414  			// ignore error
   415  			right = util.NewNil()
   416  			err = nil
   417  		}
   418  
   419  		resolvedLeftType, err := types.ResolveType(p, leftType)
   420  		if err != nil {
   421  			p.AddMessage(p.GenerateWarningMessage(err, n))
   422  		}
   423  
   424  		expr := util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt)
   425  
   426  		return expr, "bool", preStmts, postStmts, nil
   427  	}
   428  
   429  	// The right hand argument of the shift left or shift right operators
   430  	// in Go must be unsigned integers. In C, shifting with a negative shift
   431  	// count is undefined behaviour (so we should be able to ignore that case).
   432  	// To handle this, cast the shift count to a uint64.
   433  	if operator == token.SHL || // <<
   434  		operator == token.SHR || // >>
   435  		operator == token.SHL_ASSIGN || // <<=
   436  		operator == token.SHR_ASSIGN || // <<=
   437  		false {
   438  		right, err = types.CastExpr(p, right, rightType, "unsigned long long")
   439  		p.AddMessage(p.GenerateWarningMessage(err, n))
   440  		if right == nil {
   441  			right = util.NewNil()
   442  		}
   443  	}
   444  
   445  	// pointer arithmetic
   446  	if types.IsPointer(n.Type, p) {
   447  		if operator == token.ADD || // +
   448  			operator == token.SUB || // -
   449  			false {
   450  
   451  			el, extl, prel, postl, errl := atomicOperation(n.Children()[0], p)
   452  			er, extr, prer, postr, errr := atomicOperation(n.Children()[1], p)
   453  			if errl != nil || errr != nil {
   454  				err = fmt.Errorf("pointer operation is not valid : %v. %v", errl, errr)
   455  				return
   456  			}
   457  			preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, prel, postl)
   458  			preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, prer, postr)
   459  
   460  			if types.IsCPointer(extl, p) {
   461  				expr, eType, prel, postl, errl = pointerArithmetic(p, el, extl, er, extr, operator)
   462  			} else {
   463  				expr, eType, prel, postl, errl = pointerArithmetic(p, er, extr, el, extl, operator)
   464  			}
   465  
   466  			if errl != nil {
   467  				err = fmt.Errorf("pointer operation is not valid : %v", errl)
   468  				return
   469  			}
   470  
   471  			preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, prel, postl)
   472  
   473  			return
   474  		}
   475  	}
   476  
   477  	if operator == token.NEQ || // !=
   478  		operator == token.EQL || // ==
   479  		operator == token.LSS || // <
   480  		operator == token.GTR || // >
   481  		operator == token.AND || // &
   482  		operator == token.ADD || // +
   483  		operator == token.SUB || // -
   484  		operator == token.MUL || // *
   485  		operator == token.QUO || // /
   486  		operator == token.REM || // %
   487  		operator == token.LEQ || // <=
   488  		operator == token.GEQ || // >=
   489  		operator == token.ADD_ASSIGN || // +=
   490  		operator == token.SUB_ASSIGN || // -=
   491  		operator == token.MUL_ASSIGN || // *=
   492  		operator == token.QUO_ASSIGN || // /=
   493  		operator == token.REM_ASSIGN || // %=
   494  
   495  		operator == token.AND_ASSIGN || // &=
   496  		operator == token.OR_ASSIGN || // |=
   497  		operator == token.XOR_ASSIGN || // ^=
   498  		operator == token.SHL_ASSIGN || // <<=
   499  		operator == token.SHR_ASSIGN || // >>=
   500  		operator == token.AND_NOT_ASSIGN || // &^=
   501  		false {
   502  
   503  		if rightType == types.NullPointer && leftType == types.NullPointer {
   504  			// example C code :
   505  			// if ( NULL == NULL )
   506  			right = goast.NewIdent("1")
   507  			rightType = "int"
   508  			left = goast.NewIdent("1")
   509  			leftType = "int"
   510  
   511  		} else if rightType != types.NullPointer && leftType != types.NullPointer {
   512  			// We may have to cast the right side to the same type as the left
   513  			// side. This is a bit crude because we should make a better
   514  			// decision of which type to cast to instead of only using the type
   515  			// of the left side.
   516  
   517  			if operator == token.ADD || // +
   518  				operator == token.SUB || // -
   519  				operator == token.MUL || // *
   520  				operator == token.QUO || // /
   521  				operator == token.REM || // %
   522  				false {
   523  
   524  				if rightType == "bool" {
   525  					right, err = types.CastExpr(p, right, rightType, "int")
   526  					rightType = "int"
   527  					p.AddMessage(p.GenerateWarningMessage(err, n))
   528  				}
   529  				if leftType == "bool" {
   530  					left, err = types.CastExpr(p, left, leftType, "int")
   531  					leftType = "int"
   532  					p.AddMessage(p.GenerateWarningMessage(err, n))
   533  				}
   534  			}
   535  			right, err = types.CastExpr(p, right, rightType, leftType)
   536  			rightType = leftType
   537  			p.AddMessage(p.GenerateWarningMessage(err, n))
   538  
   539  			// compare pointers
   540  			//
   541  			// BinaryOperator 'int' '<'
   542  			// |-ImplicitCastExpr 'char *' <LValueToRValue>
   543  			// | `-DeclRefExpr 'char *' lvalue Var 0x26ba988 'c' 'char *'
   544  			// `-ImplicitCastExpr 'char *' <LValueToRValue>
   545  			//   `-DeclRefExpr 'char *' lvalue Var 0x26ba8a8 'b' 'char *'
   546  			if types.IsPointer(leftType, p) || types.IsPointer(rightType, p) {
   547  				err = fmt.Errorf("need add pointer operator : %s %v %s",
   548  					leftType, n.Operator, rightType)
   549  				return
   550  			}
   551  		}
   552  	}
   553  
   554  	if operator == token.ASSIGN { // =
   555  
   556  		// BinaryOperator 'double *' '='
   557  		// |-DeclRefExpr 'double *' lvalue Var 0x2a7fa48 'd' 'double *'
   558  		// `-ImplicitCastExpr 'double *' <BitCast>
   559  		//   `-CStyleCastExpr 'char *' <BitCast>
   560  		//     `-...
   561  		right, err = types.CastExpr(p, right, rightType, returnType)
   562  		rightType = returnType
   563  		if err != nil {
   564  			return
   565  		}
   566  
   567  		if _, ok := right.(*goast.UnaryExpr); ok && types.IsDereferenceType(rightType) {
   568  			deref, err := types.GetDereferenceType(rightType)
   569  
   570  			if !p.AddMessage(p.GenerateWarningMessage(err, n)) {
   571  				resolvedDeref, err := types.ResolveType(p, deref)
   572  
   573  				// FIXME: I'm not sure how this situation arises.
   574  				if resolvedDeref == "" {
   575  					resolvedDeref = "interface{}"
   576  				}
   577  
   578  				if !p.AddMessage(p.GenerateWarningMessage(err, n)) {
   579  					p.AddImport("unsafe")
   580  					right = CreateSliceFromReference(resolvedDeref, right)
   581  				}
   582  			}
   583  		}
   584  
   585  		if p.AddMessage(p.GenerateWarningMessage(err, n)) && right == nil {
   586  			right = util.NewNil()
   587  		}
   588  	}
   589  
   590  	var resolvedLeftType = n.Type
   591  	if !util.IsFunction(n.Type) && !types.IsTypedefFunction(p, n.Type) {
   592  		if leftType != types.NullPointer {
   593  			resolvedLeftType, err = types.ResolveType(p, leftType)
   594  		} else {
   595  			resolvedLeftType, err = types.ResolveType(p, rightType)
   596  		}
   597  		p.AddMessage(p.GenerateWarningMessage(err, n))
   598  	}
   599  
   600  	// Enum casting
   601  	if operator != token.ASSIGN && strings.Contains(rightType, "enum ") {
   602  		right, err = types.CastExpr(p, right, rightType, "int")
   603  		if err != nil {
   604  			p.AddMessage(p.GenerateWarningMessage(err, n))
   605  		}
   606  	}
   607  
   608  	if left == nil {
   609  		err = fmt.Errorf("left part of binary operation is nil. left : %#v", n.Children()[0])
   610  		p.AddMessage(p.GenerateWarningMessage(err, n))
   611  		return nil, "", nil, nil, err
   612  	}
   613  
   614  	if right == nil {
   615  		err = fmt.Errorf("right part of binary operation is nil. right : %#v", n.Children()[1])
   616  		p.AddMessage(p.GenerateWarningMessage(err, n))
   617  		return nil, "", nil, nil, err
   618  	}
   619  
   620  	return util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt),
   621  		types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType),
   622  		preStmts, postStmts, nil
   623  }
   624  
   625  func foundCallExpr(n ast.Node) *ast.CallExpr {
   626  	switch v := n.(type) {
   627  	case *ast.ImplicitCastExpr, *ast.CStyleCastExpr:
   628  		return foundCallExpr(n.Children()[0])
   629  	case *ast.CallExpr:
   630  		return v
   631  	}
   632  	return nil
   633  }