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

     1  // This file contains functions transpiling some general operator expressions.
     2  // See binary.go and unary.go.
     3  
     4  package transpiler
     5  
     6  import (
     7  	"fmt"
     8  	goast "go/ast"
     9  	"go/token"
    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  // ternary without middle operation
    18  //
    19  // Example:
    20  //
    21  // BinaryConditionalOperator  'int'
    22  // |-BinaryOperator 'int' '>'
    23  // | |-IntegerLiteral 'int' 19
    24  // | `-UnaryOperator 'int' prefix '-'
    25  // |   `-IntegerLiteral 'int' 9
    26  // |-OpaqueValueExpr 'int'
    27  // | `-BinaryOperator 'int' '>'
    28  // |   |-IntegerLiteral 'int' 19
    29  // |   `-UnaryOperator 'int' prefix '-'
    30  // |     `-IntegerLiteral 'int' 9
    31  // |-OpaqueValueExpr  'int'
    32  // | `-BinaryOperator  'int' '>'
    33  // |   |-IntegerLiteral 'int' 19
    34  // |   `-UnaryOperator 'int' prefix '-'
    35  // |     `-IntegerLiteral 'int' 9
    36  // `-IntegerLiteral 0x3646f70 <col:18> 'int' 23
    37  func transpileBinaryConditionalOperator(n *ast.BinaryConditionalOperator, p *program.Program) (
    38  	_ *goast.CallExpr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
    39  	defer func() {
    40  		if err != nil {
    41  			err = fmt.Errorf("cannot transpile BinaryConditionalOperator : err = %v", err)
    42  		}
    43  	}()
    44  
    45  	var co ast.ConditionalOperator
    46  	co.Type = n.Type
    47  	co.AddChild(n.Children()[0])
    48  	co.AddChild(&ast.IntegerLiteral{
    49  		Type:  co.Type,
    50  		Value: "1",
    51  	})
    52  	co.AddChild(n.Children()[3])
    53  
    54  	return transpileConditionalOperator(&co, p)
    55  }
    56  
    57  // transpileConditionalOperator transpiles a conditional (also known as a
    58  // ternary) operator:
    59  //
    60  //	a ? b : c
    61  //
    62  // We cannot simply convert these to an "if" statement because they by inside
    63  // another expression.
    64  //
    65  // Since Go does not support the ternary operator or inline "if" statements we
    66  // use a closure to work the same way.
    67  //
    68  // It is also important to note that C only evaluates the "b" or "c" condition
    69  // based on the result of "a" (from the above example).
    70  //
    71  // Example AST:
    72  // ConditionalOperator 'int'
    73  // |-ImplicitCastExpr 'int (*)(int)' <LValueToRValue>
    74  // | `-DeclRefExpr 'int (*)(int)' lvalue Var 'v' 'int (*)(int)'
    75  // |-IntegerLiteral 'int' 1
    76  // `-CallExpr 'int'
    77  //
    78  //	|-...
    79  //
    80  // ConditionalOperator 'int'
    81  // |-BinaryOperator 'int' '!='
    82  // | |-...
    83  // |-BinaryOperator 'int' '-'
    84  // | |-...
    85  // `-BinaryOperator 'int' '-'
    86  //
    87  //	|-...
    88  func transpileConditionalOperator(n *ast.ConditionalOperator, p *program.Program) (
    89  	_ *goast.CallExpr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
    90  	defer func() {
    91  		if err != nil {
    92  			err = fmt.Errorf("cannot transpile ConditionalOperator : err = %v", err)
    93  		}
    94  	}()
    95  
    96  	// a - condition
    97  	a, aType, newPre, newPost, err := atomicOperation(n.Children()[0], p)
    98  	if err != nil {
    99  		return
   100  	}
   101  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   102  
   103  	// null in C is zero
   104  	if aType == types.NullPointer {
   105  		a = &goast.BasicLit{
   106  			Kind:  token.INT,
   107  			Value: "0",
   108  		}
   109  		aType = "int"
   110  	}
   111  
   112  	a, err = types.CastExpr(p, a, aType, "bool")
   113  	if err != nil {
   114  		err = fmt.Errorf("parameter `a` : %v", err)
   115  		return
   116  	}
   117  
   118  	// b - body
   119  	b, bType, newPre, newPost, err := atomicOperation(n.Children()[1], p)
   120  	if err != nil {
   121  		err = fmt.Errorf("parameter `b` : %v", err)
   122  		return
   123  	}
   124  	// Theorephly, length is must be zero
   125  	if len(newPre) > 0 || len(newPost) > 0 {
   126  		p.AddMessage(p.GenerateWarningMessage(
   127  			fmt.Errorf("length of pre or post in body must be zero. {%d,%d}", len(newPre), len(newPost)), n))
   128  	}
   129  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   130  
   131  	if n.Type != "void" {
   132  		b, err = types.CastExpr(p, b, bType, n.Type)
   133  		if err != nil {
   134  			return
   135  		}
   136  		bType = n.Type
   137  	}
   138  
   139  	// c - else body
   140  	c, cType, newPre, newPost, err := atomicOperation(n.Children()[2], p)
   141  	if err != nil {
   142  		err = fmt.Errorf("parameter `c` : %v", err)
   143  		return nil, "", nil, nil, err
   144  	}
   145  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   146  
   147  	if n.Type != "void" {
   148  		c, err = types.CastExpr(p, c, cType, n.Type)
   149  		if err != nil {
   150  			err = fmt.Errorf("parameter `c` : %v", err)
   151  			return
   152  		}
   153  		cType = n.Type
   154  	}
   155  
   156  	// rightType - generate return type
   157  	var returnType string
   158  	if n.Type != "void" {
   159  		returnType, err = types.ResolveType(p, n.Type)
   160  		if err != nil {
   161  			return
   162  		}
   163  	}
   164  
   165  	var bod, els goast.BlockStmt
   166  
   167  	bod.Lbrace = 1
   168  	if bType != types.ToVoid {
   169  		if n.Type != "void" {
   170  			bod.List = []goast.Stmt{
   171  				&goast.ReturnStmt{
   172  					Results: []goast.Expr{b},
   173  				},
   174  			}
   175  		} else {
   176  			bod.List = []goast.Stmt{
   177  				&goast.ExprStmt{
   178  					X: b,
   179  				},
   180  			}
   181  		}
   182  	}
   183  
   184  	els.Lbrace = 1
   185  	if cType != types.ToVoid {
   186  		if n.Type != "void" {
   187  			els.List = []goast.Stmt{
   188  				&goast.ReturnStmt{
   189  					Results: []goast.Expr{c},
   190  				},
   191  			}
   192  		} else {
   193  			els.List = []goast.Stmt{
   194  				&goast.ExprStmt{
   195  					X: c,
   196  				},
   197  			}
   198  		}
   199  	}
   200  
   201  	stmts := append([]goast.Stmt{}, &goast.IfStmt{
   202  		Cond: a,
   203  		Body: &bod,
   204  		Else: &els,
   205  	})
   206  	if len(bod.List) > 0 {
   207  		if _, ok := bod.List[len(bod.List)-1].(*goast.ReturnStmt); ok {
   208  			stmts = append([]goast.Stmt{}, &goast.IfStmt{
   209  				Cond: a,
   210  				Body: &bod,
   211  			})
   212  			stmts = append(stmts, els.List...)
   213  		}
   214  	}
   215  
   216  	return util.NewFuncClosure(
   217  		returnType,
   218  		stmts...), n.Type, preStmts, postStmts, nil
   219  }
   220  
   221  // transpileParenExpr transpiles an expression that is wrapped in parentheses.
   222  // There is a special case where "(0)" is treated as a NULL (since that's what
   223  // the macro expands to). We have to return the type as "null" since we don't
   224  // know at this point what the NULL expression will be used in conjunction with.
   225  func transpileParenExpr(n *ast.ParenExpr, p *program.Program) (
   226  	r *goast.ParenExpr, exprType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   227  	defer func() {
   228  		if err != nil {
   229  			err = fmt.Errorf("cannot transpile ParenExpr. err = %v", err)
   230  			p.AddMessage(p.GenerateWarningMessage(err, n))
   231  		}
   232  	}()
   233  
   234  	n.Type = util.GenerateCorrectType(n.Type)
   235  	n.Type2 = util.GenerateCorrectType(n.Type2)
   236  
   237  	expr, exprType, preStmts, postStmts, err := atomicOperation(n.Children()[0], p)
   238  	if err != nil {
   239  		return
   240  	}
   241  	if expr == nil {
   242  		err = fmt.Errorf("expr is nil")
   243  		return
   244  	}
   245  
   246  	if exprType == types.NullPointer {
   247  		r = &goast.ParenExpr{X: expr}
   248  		return
   249  	}
   250  
   251  	if !util.IsFunction(exprType) &&
   252  		exprType != "void" &&
   253  		exprType != "bool" &&
   254  		exprType != types.ToVoid {
   255  		expr, err = types.CastExpr(p, expr, exprType, n.Type)
   256  		if err != nil {
   257  			return
   258  		}
   259  		exprType = n.Type
   260  	}
   261  
   262  	var ok bool
   263  	r, ok = expr.(*goast.ParenExpr)
   264  	if !ok {
   265  		r = &goast.ParenExpr{X: expr}
   266  	}
   267  
   268  	return
   269  }
   270  
   271  func transpileCompoundAssignOperator(
   272  	n *ast.CompoundAssignOperator, p *program.Program, exprIsStmt bool) (
   273  	_ goast.Expr, _ string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   274  
   275  	defer func() {
   276  		if err != nil {
   277  			err = fmt.Errorf("cannot transpileCompoundAssignOperator. err = %v", err)
   278  		}
   279  	}()
   280  
   281  	operator := n.Opcode[:len(n.Opcode)-1]
   282  
   283  	if len(n.ChildNodes) != 2 {
   284  		err = fmt.Errorf("not enought ChildNodes: %d", len(n.ChildNodes))
   285  		return
   286  	}
   287  
   288  	if !types.IsCPointer(n.Type, p) && !types.IsCArray(n.Type, p) {
   289  		return transpileBinaryOperator(&ast.BinaryOperator{
   290  			Type:       n.Type,
   291  			Operator:   n.Opcode,
   292  			ChildNodes: n.ChildNodes,
   293  		}, p, false)
   294  	}
   295  
   296  	return transpileBinaryOperator(&ast.BinaryOperator{
   297  		Type:     n.Type,
   298  		Operator: "=",
   299  		ChildNodes: []ast.Node{
   300  			n.ChildNodes[0],
   301  			&ast.BinaryOperator{
   302  				Type:       n.Type,
   303  				Operator:   operator,
   304  				ChildNodes: n.ChildNodes,
   305  			},
   306  		},
   307  	}, p, false)
   308  }
   309  
   310  func getTokenForOperatorNoError(operator string) token.Token {
   311  	t, err := getTokenForOperator(operator)
   312  	if err != nil {
   313  		return token.XOR
   314  	}
   315  	return t
   316  }
   317  
   318  // getTokenForOperator returns the Go operator token for the provided C
   319  // operator.
   320  func getTokenForOperator(operator string) (t token.Token, err error) {
   321  	switch operator {
   322  	// Arithmetic
   323  	case "--":
   324  		return token.DEC, nil
   325  	case "++":
   326  		return token.INC, nil
   327  	case "+":
   328  		return token.ADD, nil
   329  	case "-":
   330  		return token.SUB, nil
   331  	case "*":
   332  		return token.MUL, nil
   333  	case "/":
   334  		return token.QUO, nil
   335  	case "%":
   336  		return token.REM, nil
   337  
   338  	// Assignment
   339  	case "=":
   340  		return token.ASSIGN, nil
   341  	case "+=":
   342  		return token.ADD_ASSIGN, nil
   343  	case "-=":
   344  		return token.SUB_ASSIGN, nil
   345  	case "*=":
   346  		return token.MUL_ASSIGN, nil
   347  	case "/=":
   348  		return token.QUO_ASSIGN, nil
   349  	case "%=":
   350  		return token.REM_ASSIGN, nil
   351  	case "&=":
   352  		return token.AND_ASSIGN, nil
   353  	case "|=":
   354  		return token.OR_ASSIGN, nil
   355  	case "^=":
   356  		return token.XOR_ASSIGN, nil
   357  	case "<<=":
   358  		return token.SHL_ASSIGN, nil
   359  	case ">>=":
   360  		return token.SHR_ASSIGN, nil
   361  
   362  	// Bitwise
   363  	case "&":
   364  		return token.AND, nil
   365  	case "|":
   366  		return token.OR, nil
   367  	case "~":
   368  		return token.XOR, nil
   369  	case ">>":
   370  		return token.SHR, nil
   371  	case "<<":
   372  		return token.SHL, nil
   373  	case "^":
   374  		return token.XOR, nil
   375  
   376  	// Comparison
   377  	case ">=":
   378  		return token.GEQ, nil
   379  	case "<=":
   380  		return token.LEQ, nil
   381  	case "<":
   382  		return token.LSS, nil
   383  	case ">":
   384  		return token.GTR, nil
   385  	case "!=":
   386  		return token.NEQ, nil
   387  	case "==":
   388  		return token.EQL, nil
   389  
   390  	// Logical
   391  	case "!":
   392  		return token.NOT, nil
   393  	case "&&":
   394  		return token.LAND, nil
   395  	case "||":
   396  		return token.LOR, nil
   397  
   398  	// Other
   399  	case ",":
   400  		return token.COMMA, nil
   401  	}
   402  
   403  	err = fmt.Errorf("unknown operator: %s and replaced to XOR operator\n", operator)
   404  	return
   405  }
   406  
   407  func convertToWithoutAssign(operator token.Token) token.Token {
   408  	switch operator {
   409  	case token.ADD_ASSIGN: // "+="
   410  		return token.ADD
   411  	case token.SUB_ASSIGN: // "-="
   412  		return token.SUB
   413  	case token.MUL_ASSIGN: // "*="
   414  		return token.MUL
   415  	case token.QUO_ASSIGN: // "/="
   416  		return token.QUO
   417  	}
   418  	panic(fmt.Sprintf("not support operator: %v", operator))
   419  }
   420  
   421  func findUnaryWithInteger(node ast.Node) (*ast.UnaryOperator, bool) {
   422  	switch n := node.(type) {
   423  	case *ast.UnaryOperator:
   424  		return n, true
   425  	case *ast.ParenExpr:
   426  		return findUnaryWithInteger(n.Children()[0])
   427  	}
   428  	return nil, false
   429  }
   430  
   431  func atomicOperation(n ast.Node, p *program.Program) (
   432  	expr goast.Expr, exprType string, preStmts, postStmts []goast.Stmt, err error) {
   433  
   434  	expr, exprType, preStmts, postStmts, err = transpileToExpr(n, p, false)
   435  	if err != nil {
   436  		return
   437  	}
   438  
   439  	defer func() {
   440  		if err != nil {
   441  			err = fmt.Errorf("cannot create atomicOperation |%T|. err = %v", n, err)
   442  		}
   443  		if exprType == "" {
   444  			p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("exprType is empty"), n))
   445  		}
   446  	}()
   447  
   448  	switch v := n.(type) {
   449  	case *ast.UnaryOperator:
   450  		switch v.Operator {
   451  		case "&", "*", "!", "-", "+", "~":
   452  			return
   453  		}
   454  		// UnaryOperator 0x252d798 <col:17, col:18> 'double' prefix '-'
   455  		// `-FloatingLiteral 0x252d778 <col:18> 'double' 0.000000e+00
   456  		if _, ok := v.Children()[0].(*ast.IntegerLiteral); ok {
   457  			return
   458  		}
   459  		if _, ok := v.Children()[0].(*ast.FloatingLiteral); ok {
   460  			return
   461  		}
   462  
   463  		// UnaryOperator 0x3001768 <col:204, col:206> 'int' prefix '++'
   464  		// `-DeclRefExpr 0x3001740 <col:206> 'int' lvalue Var 0x303e888 'current_test' 'int'
   465  		// OR
   466  		// UnaryOperator 0x3001768 <col:204, col:206> 'int' postfix '++'
   467  		// `-DeclRefExpr 0x3001740 <col:206> 'int' lvalue Var 0x303e888 'current_test' 'int'
   468  		var varName string
   469  		if vv, ok := v.Children()[0].(*ast.DeclRefExpr); ok {
   470  			varName = vv.Name
   471  
   472  			var exprResolveType string
   473  			exprResolveType, err = types.ResolveType(p, v.Type)
   474  			if err != nil {
   475  				return
   476  			}
   477  
   478  			// operators: ++, --
   479  			if v.IsPrefix {
   480  				// Example:
   481  				// UnaryOperator 0x3001768 <col:204, col:206> 'int' prefix '++'
   482  				// `-DeclRefExpr 0x3001740 <col:206> 'int' lvalue Var 0x303e888 'current_test' 'int'
   483  				expr = util.NewAnonymousFunction(
   484  					append(preStmts, &goast.ExprStmt{X: expr}),
   485  					nil,
   486  					util.NewIdent(varName),
   487  					exprResolveType)
   488  				preStmts = nil
   489  				break
   490  			}
   491  			// Example:
   492  			// UnaryOperator 0x3001768 <col:204, col:206> 'int' postfix '++'
   493  			// `-DeclRefExpr 0x3001740 <col:206> 'int' lvalue Var 0x303e888 'current_test' 'int'
   494  			expr = util.NewAnonymousFunction(preStmts,
   495  				[]goast.Stmt{&goast.ExprStmt{X: expr}},
   496  				util.NewIdent(varName),
   497  				exprResolveType)
   498  			preStmts = nil
   499  
   500  			break
   501  		}
   502  
   503  		// UnaryOperator 'char *' postfix '++'
   504  		// `-ParenExpr 'char *' lvalue
   505  		//   `-UnaryOperator 'char *' lvalue prefix '*'
   506  		//     `-ImplicitCastExpr 'char **' <LValueToRValue>
   507  		//       `-DeclRefExpr 'char **' lvalue Var 0x2699168 'bpp' 'char **'
   508  		//
   509  		// UnaryOperator 'int' postfix '++'
   510  		// `-MemberExpr 'int' lvalue .pos 0x358b538
   511  		//   `-ArraySubscriptExpr 'struct struct_I_A':'struct struct_I_A' lvalue
   512  		//     |-ImplicitCastExpr 'struct struct_I_A *' <ArrayToPointerDecay>
   513  		//     | `-DeclRefExpr 'struct struct_I_A [2]' lvalue Var 0x358b6e8 'siia' 'struct struct_I_A [2]'
   514  		//     `-IntegerLiteral 'int' 0
   515  		varName = "tempVar1"
   516  
   517  		nextNode := v.Children()[0]
   518  		for {
   519  			if par, ok := nextNode.(*ast.ParenExpr); ok {
   520  				nextNode = par.ChildNodes[0]
   521  				continue
   522  			}
   523  			break
   524  		}
   525  		expr, exprType, preStmts, postStmts, err = transpileToExpr(nextNode, p, false)
   526  		if err != nil {
   527  			return
   528  		}
   529  
   530  		var exprResolveType string
   531  		exprResolveType, err = types.ResolveType(p, v.Type)
   532  		if err != nil {
   533  			return
   534  		}
   535  
   536  		if v.Operator == "__extension__" {
   537  			// `-ImplicitCastExpr 0x27aea88 <> 'const char *' <ArrayToPointerDecay>
   538  			//   `-UnaryOperator 0x27ae970 <> 'const char [18]' lvalue prefix '__extension__' cannot overfl
   539  			//
   540  			//     `-PredefinedExpr 0x27ae958 <> 'const char [18]' lvalue __PRETTY_FUNCTION__
   541  			//       `-StringLiteral 0x27ae928 <> 'const char [18]' lvalue "void handler(int)"
   542  			preStmts = nil
   543  			postStmts = nil
   544  			return
   545  		}
   546  
   547  		if types.IsPointer(v.Type, p) {
   548  			switch e := expr.(type) {
   549  			case *goast.IndexExpr:
   550  				if v.Operator == "++" {
   551  					// expr = 'bpp[0]'
   552  					// example of snippet:
   553  					//	func  () []byte{
   554  					//		tempVar = bpp[0]
   555  					//		defer func(){
   556  					//			bpp = bpp[1:]
   557  					//		}()
   558  					//		return tempVar
   559  					//	}
   560  					expr = util.NewAnonymousFunction(
   561  						// body :
   562  						append(preStmts, &goast.AssignStmt{
   563  							Lhs: []goast.Expr{util.NewIdent(varName)},
   564  							Tok: token.DEFINE,
   565  							Rhs: []goast.Expr{expr},
   566  						}),
   567  						// defer :
   568  						append([]goast.Stmt{
   569  							&goast.AssignStmt{
   570  								Lhs: []goast.Expr{
   571  									e,
   572  								},
   573  								Tok: token.ASSIGN,
   574  								Rhs: []goast.Expr{
   575  									&goast.SliceExpr{
   576  										X:      e,
   577  										Low:    goast.NewIdent("1"),
   578  										Slice3: false,
   579  									},
   580  								},
   581  							},
   582  						}, postStmts...),
   583  						// return :
   584  						util.NewIdent(varName),
   585  						exprResolveType)
   586  					preStmts = nil
   587  					postStmts = nil
   588  					return
   589  				}
   590  
   591  			case *goast.Ident, *goast.SelectorExpr:
   592  				if v.Operator == "++" {
   593  					// expr = 'p'
   594  					// example of snippet:
   595  					//	func  () [][]byte{
   596  					//		tempVar = p
   597  					//		defer func(){
   598  					//			p = p[1:]
   599  					//		}()
   600  					//		return tempVar
   601  					//	}
   602  					expr = util.NewAnonymousFunction(
   603  						// body :
   604  						append(preStmts, &goast.AssignStmt{
   605  							Lhs: []goast.Expr{util.NewIdent(varName)},
   606  							Tok: token.DEFINE,
   607  							Rhs: []goast.Expr{expr},
   608  						}),
   609  						// defer :
   610  						append([]goast.Stmt{
   611  							&goast.AssignStmt{
   612  								Lhs: []goast.Expr{
   613  									e,
   614  								},
   615  								Tok: token.ASSIGN,
   616  								Rhs: []goast.Expr{
   617  									&goast.SliceExpr{
   618  										X:      e,
   619  										Low:    goast.NewIdent("1"),
   620  										Slice3: false,
   621  									},
   622  								},
   623  							},
   624  						}, postStmts...),
   625  						// return :
   626  						util.NewIdent(varName),
   627  						exprResolveType)
   628  					preStmts = nil
   629  					postStmts = nil
   630  					return
   631  				}
   632  
   633  			default:
   634  				// TODO add here
   635  				p.AddMessage(p.GenerateWarningMessage(
   636  					fmt.Errorf("transpilation pointer is not support: %T", e), v))
   637  			}
   638  		}
   639  
   640  		body := append(preStmts, &goast.AssignStmt{
   641  			Lhs: []goast.Expr{util.NewIdent(varName)},
   642  			Tok: token.DEFINE,
   643  			Rhs: []goast.Expr{util.NewUnaryExpr(
   644  				expr,
   645  				token.AND,
   646  			)},
   647  		})
   648  
   649  		deferBody := postStmts
   650  		postStmts = nil
   651  		preStmts = nil
   652  
   653  		switch v.Operator {
   654  		case "++":
   655  			expr = &goast.BinaryExpr{
   656  				X:  &goast.StarExpr{X: util.NewIdent(varName)},
   657  				Op: token.ADD_ASSIGN,
   658  				Y:  &goast.BasicLit{Kind: token.INT, Value: "1"},
   659  			}
   660  		case "--":
   661  			expr = &goast.BinaryExpr{
   662  				X:  &goast.StarExpr{X: util.NewIdent(varName)},
   663  				Op: token.SUB_ASSIGN,
   664  				Y:  &goast.BasicLit{Kind: token.INT, Value: "1"},
   665  			}
   666  		}
   667  
   668  		body = append(body, preStmts...)
   669  		deferBody = append(deferBody, postStmts...)
   670  
   671  		// operators: ++, --
   672  		if v.IsPrefix {
   673  			// Example:
   674  			// UnaryOperator 0x3001768 <col:204, col:206> 'int' prefix '++'
   675  			// `-DeclRefExpr 0x3001740 <col:206> 'int' lvalue Var 0x303e888 'current_test' 'int'
   676  			expr = util.NewAnonymousFunction(
   677  				append(body, &goast.ExprStmt{X: expr}),
   678  				deferBody,
   679  				&goast.StarExpr{
   680  					X: util.NewIdent(varName),
   681  				},
   682  				exprResolveType)
   683  			preStmts = nil
   684  			postStmts = nil
   685  			break
   686  		}
   687  		// Example:
   688  		// UnaryOperator 0x3001768 <col:204, col:206> 'int' postfix '++'
   689  		// `-DeclRefExpr 0x3001740 <col:206> 'int' lvalue Var 0x303e888 'current_test' 'int'
   690  		expr = util.NewAnonymousFunction(body,
   691  			append(deferBody, &goast.ExprStmt{X: expr}),
   692  			&goast.StarExpr{
   693  				X: util.NewIdent(varName),
   694  			},
   695  			exprResolveType)
   696  		preStmts = nil
   697  		postStmts = nil
   698  
   699  	case *ast.CompoundAssignOperator:
   700  		// CompoundAssignOperator 0x32911c0 <col:18, col:28> 'int' '-=' ComputeLHSTy='int' ComputeResultTy='int'
   701  		// |-DeclRefExpr 0x3291178 <col:18> 'int' lvalue Var 0x328df60 'iterator' 'int'
   702  		// `-IntegerLiteral 0x32911a0 <col:28> 'int' 2
   703  		if vv, ok := v.Children()[0].(*ast.DeclRefExpr); ok {
   704  			varName := vv.Name
   705  
   706  			var exprResolveType string
   707  			exprResolveType, err = types.ResolveType(p, v.Type)
   708  			if err != nil {
   709  				return
   710  			}
   711  
   712  			expr = util.NewAnonymousFunction(
   713  				append(preStmts, &goast.ExprStmt{X: expr}),
   714  				postStmts,
   715  				util.NewIdent(varName),
   716  				exprResolveType)
   717  			preStmts = nil
   718  			postStmts = nil
   719  			break
   720  		}
   721  		// CompoundAssignOperator 0x27906c8 <line:450:2, col:6> 'double' '+=' ComputeLHSTy='double' ComputeResultTy='double'
   722  		// |-UnaryOperator 0x2790670 <col:2, col:3> 'double' lvalue prefix '*'
   723  		// | `-ImplicitCastExpr 0x2790658 <col:3> 'double *' <LValueToRValue>
   724  		// |   `-DeclRefExpr 0x2790630 <col:3> 'double *' lvalue Var 0x2790570 'p' 'double *'
   725  		// `-IntegerLiteral 0x32911a0 <col:28> 'int' 2
   726  		if vv, ok := v.Children()[0].(*ast.UnaryOperator); ok && vv.IsPrefix && vv.Operator == "*" {
   727  			if vvv, ok := vv.Children()[0].(*ast.ImplicitCastExpr); ok {
   728  				if vvvv, ok := vvv.Children()[0].(*ast.DeclRefExpr); ok {
   729  					if types.IsPointer(vvvv.Type, p) {
   730  						varName := vvvv.Name
   731  
   732  						var exprResolveType string
   733  						exprResolveType, err = types.ResolveType(p, v.Type)
   734  						if err != nil {
   735  							return
   736  						}
   737  
   738  						expr = util.NewAnonymousFunction(
   739  							append(preStmts, &goast.ExprStmt{X: expr}),
   740  							postStmts,
   741  							util.NewUnaryExpr(
   742  								util.NewIdent(varName),
   743  								token.AND,
   744  							),
   745  							exprResolveType)
   746  						preStmts = nil
   747  						postStmts = nil
   748  						break
   749  					}
   750  				}
   751  			}
   752  		}
   753  
   754  		// CompoundAssignOperator 0x32911c0 <col:18, col:28> 'int' '-=' ComputeLHSTy='int' ComputeResultTy='int'
   755  		// |-DeclRefExpr 0x3291178 <col:18> 'int' lvalue Var 0x328df60 'iterator' 'int'
   756  		// `-IntegerLiteral 0x32911a0 <col:28> 'int' 2
   757  		varName := "tempVar2"
   758  		expr, exprType, preStmts, postStmts, err = transpileToExpr(v.Children()[0], p, false)
   759  		if err != nil {
   760  			return
   761  		}
   762  		body := append(preStmts, &goast.AssignStmt{
   763  			Lhs: []goast.Expr{util.NewIdent(varName)},
   764  			Tok: token.DEFINE,
   765  			Rhs: []goast.Expr{util.NewUnaryExpr(expr, token.AND)},
   766  		})
   767  		preStmts = nil
   768  
   769  		// CompoundAssignOperator 0x27906c8 <line:450:2, col:6> 'double' '+=' ComputeLHSTy='double' ComputeResultTy='double'
   770  		// |-UnaryOperator 0x2790670 <col:2, col:3> 'double' lvalue prefix '*'
   771  		// | `-ImplicitCastExpr 0x2790658 <col:3> 'double *' <LValueToRValue>
   772  		// |   `-DeclRefExpr 0x2790630 <col:3> 'double *' lvalue Var 0x2790570 'p' 'double *'
   773  		// `-ImplicitCastExpr 0x27906b0 <col:6> 'double' <IntegralToFloating>
   774  		//   `-IntegerLiteral 0x2790690 <col:6> 'int' 1
   775  		var newPre, newPost []goast.Stmt
   776  		expr, exprType, newPre, newPost, err = atomicOperation(v.Children()[1], p)
   777  		if err != nil {
   778  			return
   779  		}
   780  		preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   781  
   782  		var exprResolveType string
   783  		exprResolveType, err = types.ResolveType(p, v.Type)
   784  		if err != nil {
   785  			return
   786  		}
   787  
   788  		body = append(preStmts, body...)
   789  		body = append(body, &goast.AssignStmt{
   790  			Lhs: []goast.Expr{&goast.StarExpr{
   791  				X: util.NewIdent(varName),
   792  			}},
   793  			Tok: getTokenForOperatorNoError(v.Opcode),
   794  			Rhs: []goast.Expr{expr},
   795  		})
   796  
   797  		expr = util.NewAnonymousFunction(body, postStmts,
   798  			&goast.StarExpr{
   799  				X: util.NewIdent(varName),
   800  			},
   801  			exprResolveType)
   802  		preStmts = nil
   803  		postStmts = nil
   804  
   805  	case *ast.ParenExpr:
   806  		// ParenExpr 0x3c42468 <col:18, col:40> 'int'
   807  		if len(n.Children()) == 1 {
   808  			return atomicOperation(n.Children()[0], p)
   809  		}
   810  		return
   811  
   812  	case *ast.ImplicitCastExpr:
   813  		if _, ok := v.Children()[0].(*ast.MemberExpr); ok {
   814  			return
   815  		}
   816  		if _, ok := v.Children()[0].(*ast.IntegerLiteral); ok {
   817  			return
   818  		}
   819  		if v.Kind == "IntegralToPointer" {
   820  			return
   821  		}
   822  		if v.Kind == "BitCast" {
   823  			return
   824  		}
   825  
   826  		v.Type = util.GenerateCorrectType(v.Type)
   827  		v.Type2 = util.GenerateCorrectType(v.Type2)
   828  
   829  		// avoid problem :
   830  		//
   831  		// constant -1331 overflows uint32
   832  		//
   833  		// ImplicitCastExpr 'unsigned int' <IntegralCast>
   834  		// `-UnaryOperator 'int' prefix '~'
   835  		if t, ok := ast.GetTypeIfExist(v.Children()[0]); ok && !types.IsSigned(p, v.Type) && types.IsSigned(p, *t) {
   836  			if un, ok := n.Children()[0].(*ast.UnaryOperator); ok && un.Operator == "~" {
   837  				var goType string
   838  				goType, err = types.ResolveType(p, v.Type)
   839  				if err != nil {
   840  					return
   841  				}
   842  				expr = util.ConvertToUnsigned(expr, goType)
   843  				return
   844  			}
   845  		}
   846  
   847  		// for case : overflow char
   848  		// ImplicitCastExpr 0x2027358 <col:6, col:7> 'char' <IntegralCast>
   849  		// `-UnaryOperator 0x2027338 <col:6, col:7> 'int' prefix '-'
   850  		//   `-IntegerLiteral 0x2027318 <col:7> 'int' 1
   851  		//
   852  		// another example :
   853  		// ImplicitCastExpr 0x2982630 <col:11, col:14> 'char' <IntegralCast>
   854  		// `-ParenExpr 0x2982610 <col:11, col:14> 'int'
   855  		//   `-UnaryOperator 0x29825f0 <col:12, col:13> 'int' prefix '-'
   856  		//     `-IntegerLiteral 0x29825d0 <col:13> 'int' 1
   857  		if v.Type == "char" {
   858  			if len(v.Children()) == 1 {
   859  				if u, ok := findUnaryWithInteger(n.Children()[0]); ok {
   860  					if u.IsPrefix && u.Type == "int" && u.Operator == "-" {
   861  						if _, ok := u.Children()[0].(*ast.IntegerLiteral); ok {
   862  							return transpileToExpr(&ast.BinaryOperator{
   863  								Type:     "int",
   864  								Type2:    "int",
   865  								Operator: "+",
   866  								ChildNodes: []ast.Node{
   867  									u,
   868  									&ast.IntegerLiteral{
   869  										Type:  "int",
   870  										Value: "256",
   871  									},
   872  								},
   873  							}, p, false)
   874  						}
   875  					}
   876  				}
   877  			}
   878  		}
   879  
   880  		var isSameBaseType bool
   881  		if impl, ok := v.Children()[0].(*ast.ImplicitCastExpr); ok {
   882  			if types.GetBaseType(v.Type) == types.GetBaseType(impl.Type) {
   883  				isSameBaseType = true
   884  			}
   885  		}
   886  
   887  		if v.Kind == "PointerToIntegral" {
   888  			if isSameBaseType {
   889  				expr = &goast.IndexExpr{
   890  					X:      expr,
   891  					Lbrack: 1,
   892  					Index: &goast.BasicLit{
   893  						Kind:  token.INT,
   894  						Value: "0",
   895  					},
   896  				}
   897  				exprType = v.Type
   898  				return
   899  			}
   900  			expr = goast.NewIdent("0")
   901  			expr, _ = types.CastExpr(p, expr, "int", v.Type)
   902  			exprType = v.Type
   903  			return
   904  		}
   905  
   906  		expr, exprType, preStmts, postStmts, err = atomicOperation(v.Children()[0], p)
   907  		if err != nil {
   908  			return nil, "", nil, nil, err
   909  		}
   910  		if exprType == types.NullPointer {
   911  			return
   912  		}
   913  
   914  		var cast bool = true
   915  		if util.IsFunction(exprType) {
   916  			cast = false
   917  		}
   918  		if v.Kind == ast.ImplicitCastExprArrayToPointerDecay {
   919  			cast = false
   920  		}
   921  
   922  		if cast {
   923  			expr, err = types.CastExpr(p, expr, exprType, v.Type)
   924  			if err != nil {
   925  				return nil, "", nil, nil, err
   926  			}
   927  			exprType = v.Type
   928  		}
   929  		return
   930  
   931  	case *ast.BinaryOperator:
   932  		defer func() {
   933  			if err != nil {
   934  				err = fmt.Errorf("binary operator : `%v`. %v", v.Operator, err)
   935  			}
   936  		}()
   937  		switch v.Operator {
   938  		case ",":
   939  			// BinaryOperator 0x35b95e8 <col:29, col:51> 'int' ','
   940  			// |-UnaryOperator 0x35b94b0 <col:29, col:31> 'int' postfix '++'
   941  			// | `-DeclRefExpr 0x35b9488 <col:29> 'int' lvalue Var 0x35b8dc8 't' 'int'
   942  			// `-CompoundAssignOperator 0x35b95b0 <col:36, col:51> 'int' '+=' ComputeLHSTy='int' ComputeResultTy='int'
   943  			//   |-MemberExpr 0x35b9558 <col:36, col:44> 'int' lvalue .pos 0x35b8730
   944  			//   | `-ArraySubscriptExpr 0x35b9530 <col:36, col:42> 'struct struct_I_A4':'struct struct_I_A4' lvalue
   945  			//   |   |-ImplicitCastExpr 0x35b9518 <col:36> 'struct struct_I_A4 *' <ArrayToPointerDecay>
   946  			//   |   | `-DeclRefExpr 0x35b94d0 <col:36> 'struct struct_I_A4 [2]' lvalue Var 0x35b88d8 'siia' 'struct struct_I_A4 [2]'
   947  			//   |   `-IntegerLiteral 0x35b94f8 <col:41> 'int' 0
   948  			//   `-IntegerLiteral 0x35b9590 <col:51> 'int' 1
   949  
   950  			// `-BinaryOperator 0x3c42440 <col:19, col:32> 'int' ','
   951  			//   |-BinaryOperator 0x3c423d8 <col:19, col:30> 'int' '='
   952  			//   | |-DeclRefExpr 0x3c42390 <col:19> 'int' lvalue Var 0x3c3cf60 'iterator' 'int'
   953  			//   | `-IntegerLiteral 0x3c423b8 <col:30> 'int' 0
   954  			//   `-ImplicitCastExpr 0x3c42428 <col:32> 'int' <LValueToRValue>
   955  			//     `-DeclRefExpr 0x3c42400 <col:32> 'int' lvalue Var 0x3c3cf60 'iterator' 'int'
   956  			varName := "tempVar3"
   957  
   958  			expr, exprType, preStmts, postStmts, err = transpileToExpr(v.Children()[0], p, false)
   959  			if err != nil {
   960  				return
   961  			}
   962  
   963  			inBody := combineStmts(preStmts, &goast.ExprStmt{X: expr}, postStmts)
   964  
   965  			expr, exprType, preStmts, postStmts, err = atomicOperation(v.Children()[1], p)
   966  			if err != nil {
   967  				return
   968  			}
   969  
   970  			if v, ok := expr.(*goast.CallExpr); ok {
   971  				if vv, ok := v.Fun.(*goast.FuncLit); ok {
   972  					vv.Body.List = append(inBody, vv.Body.List...)
   973  					break
   974  				}
   975  			}
   976  
   977  			body := append(inBody, preStmts...)
   978  			preStmts = nil
   979  
   980  			body = append(body, &goast.AssignStmt{
   981  				Lhs: []goast.Expr{util.NewIdent(varName)},
   982  				Tok: token.DEFINE,
   983  				Rhs: []goast.Expr{util.NewUnaryExpr(expr, token.AND)},
   984  			})
   985  
   986  			var exprResolveType string
   987  			exprResolveType, err = types.ResolveType(p, v.Type)
   988  			if err != nil {
   989  				err = fmt.Errorf("exprResolveType error for type `%v`: %v", v.Type, err)
   990  				return
   991  			}
   992  
   993  			expr = util.NewAnonymousFunction(body, postStmts,
   994  				util.NewUnaryExpr(util.NewIdent(varName), token.MUL),
   995  				exprResolveType)
   996  			preStmts = nil
   997  			postStmts = nil
   998  			exprType = v.Type
   999  			return
  1000  
  1001  		case "=":
  1002  			// Find ast.DeclRefExpr in Children[0]
  1003  			// Or
  1004  			// Find ast.ArraySubscriptExpr in Children[0]
  1005  			decl, ok := getDeclRefExprOrArraySub(v.Children()[0])
  1006  			if !ok {
  1007  				return
  1008  			}
  1009  			// BinaryOperator 0x2a230c0 <col:8, col:13> 'int' '='
  1010  			// |-UnaryOperator 0x2a23080 <col:8, col:9> 'int' lvalue prefix '*'
  1011  			// | `-ImplicitCastExpr 0x2a23068 <col:9> 'int *' <LValueToRValue>
  1012  			// |   `-DeclRefExpr 0x2a23040 <col:9> 'int *' lvalue Var 0x2a22f20 'a' 'int *'
  1013  			// `-IntegerLiteral 0x2a230a0 <col:13> 'int' 42
  1014  
  1015  			// VarDecl 0x328dc50 <col:3, col:29> col:13 used d 'int' cinit
  1016  			// `-BinaryOperator 0x328dd98 <col:17, col:29> 'int' '='
  1017  			//   |-DeclRefExpr 0x328dcb0 <col:17> 'int' lvalue Var 0x328dae8 'a' 'int'
  1018  			//   `-BinaryOperator 0x328dd70 <col:21, col:29> 'int' '='
  1019  			//     |-DeclRefExpr 0x328dcd8 <col:21> 'int' lvalue Var 0x328db60 'b' 'int'
  1020  			//     `-BinaryOperator 0x328dd48 <col:25, col:29> 'int' '='
  1021  			//       |-DeclRefExpr 0x328dd00 <col:25> 'int' lvalue Var 0x328dbd8 'c' 'int'
  1022  			//       `-IntegerLiteral 0x328dd28 <col:29> 'int' 42
  1023  
  1024  			// BinaryOperator 0x364a878 <line:139:7, col:23> 'int' '=='
  1025  			// |-ParenExpr 0x364a838 <col:7, col:18> 'int'
  1026  			// | `-BinaryOperator 0x364a810 <col:8, col:17> 'int' '='
  1027  			// |   |-ArraySubscriptExpr 0x364a740 <col:8, col:11> 'int' lvalue
  1028  			// |   | |-ImplicitCastExpr 0x364a728 <col:8> 'int *' <ArrayToPointerDecay>
  1029  			// |   | | `-DeclRefExpr 0x364a6e0 <col:8> 'int [5]' lvalue Var 0x3648ea0 'l' 'int [5]'
  1030  			// |   | `-IntegerLiteral 0x364a708 <col:10> 'int' 0
  1031  			// |   `-BinaryOperator 0x364a7e8 <col:15, col:17> 'int' '-'
  1032  			// |     |-ImplicitCastExpr 0x364a7b8 <col:15> 'int' <LValueToRValue>
  1033  			// |     | `-DeclRefExpr 0x364a768 <col:15> 'int' lvalue Var 0x3647c00 'y' 'int'
  1034  			// |     `-ImplicitCastExpr 0x364a7d0 <col:17> 'int' <LValueToRValue>
  1035  			// |       `-DeclRefExpr 0x364a790 <col:17> 'int' lvalue Var 0x364a648 's' 'int'
  1036  			// `-IntegerLiteral 0x364a858 <col:23> 'int' 3
  1037  
  1038  			var exprResolveType string
  1039  			exprResolveType, err = types.ResolveType(p, v.Type)
  1040  			if err != nil {
  1041  				return
  1042  			}
  1043  
  1044  			e, _, newPre, newPost, _ := transpileToExpr(v, p, false)
  1045  			body := combineStmts(newPre, &goast.ExprStmt{X: e}, newPost)
  1046  
  1047  			preStmts = nil
  1048  			postStmts = nil
  1049  
  1050  			var returnValue goast.Expr
  1051  			if bin, ok := e.(*goast.BinaryExpr); ok {
  1052  				returnValue = bin.X
  1053  			} else {
  1054  				returnValue, _, _, _, _ = transpileToExpr(decl, p, false)
  1055  				if d, ok := decl.(*ast.DeclRefExpr); ok &&
  1056  					types.IsPointer(d.Type, p) && !types.IsPointer(v.Type, p) {
  1057  					returnValue = &goast.IndexExpr{
  1058  						X: returnValue,
  1059  						Index: &goast.BasicLit{
  1060  							Kind:  token.INT,
  1061  							Value: "0",
  1062  						},
  1063  					}
  1064  				}
  1065  			}
  1066  
  1067  			expr = util.NewAnonymousFunction(body,
  1068  				nil,
  1069  				returnValue,
  1070  				exprResolveType)
  1071  			expr = &goast.ParenExpr{
  1072  				X:      expr,
  1073  				Lparen: 1,
  1074  			}
  1075  		}
  1076  
  1077  	}
  1078  
  1079  	return
  1080  }
  1081  
  1082  // getDeclRefExprOrArraySub - find ast DeclRefExpr
  1083  // Examples of input ast trees:
  1084  // UnaryOperator 0x2a23080 <col:8, col:9> 'int' lvalue prefix '*'
  1085  // `-ImplicitCastExpr 0x2a23068 <col:9> 'int *' <LValueToRValue>
  1086  //
  1087  //	`-DeclRefExpr 0x2a23040 <col:9> 'int *' lvalue Var 0x2a22f20 'a' 'int *'
  1088  //
  1089  // DeclRefExpr 0x328dd00 <col:25> 'int' lvalue Var 0x328dbd8 'c' 'int'
  1090  func getDeclRefExprOrArraySub(n ast.Node) (ast.Node, bool) {
  1091  	switch v := n.(type) {
  1092  	case *ast.DeclRefExpr:
  1093  		return v, true
  1094  	case *ast.ParenExpr:
  1095  		return getDeclRefExprOrArraySub(n.Children()[0])
  1096  	case *ast.ImplicitCastExpr:
  1097  		return getDeclRefExprOrArraySub(n.Children()[0])
  1098  	case *ast.UnaryOperator:
  1099  		return getDeclRefExprOrArraySub(n.Children()[0])
  1100  	case *ast.ArraySubscriptExpr:
  1101  		return v, true
  1102  	case *ast.BinaryOperator:
  1103  		for i := range v.Children() {
  1104  			if v, ok := getDeclRefExprOrArraySub(v.Children()[i]); ok {
  1105  				return v, true
  1106  			}
  1107  		}
  1108  	case *ast.MemberExpr:
  1109  		return v, true
  1110  	}
  1111  	return nil, false
  1112  }