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

     1  // This file contains functions for transpiling function calls (invocations).
     2  
     3  package transpiler
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	goast "go/ast"
     9  	"go/printer"
    10  	"go/token"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/Konstantin8105/c4go/ast"
    15  	"github.com/Konstantin8105/c4go/program"
    16  	"github.com/Konstantin8105/c4go/types"
    17  	"github.com/Konstantin8105/c4go/util"
    18  )
    19  
    20  func getMemberName(firstChild ast.Node) (name string, ok bool) {
    21  	switch fc := firstChild.(type) {
    22  	case *ast.MemberExpr:
    23  		return fc.Name, true
    24  
    25  	case *ast.ParenExpr:
    26  		return getMemberName(fc.Children()[0])
    27  
    28  	case *ast.ImplicitCastExpr:
    29  		return getMemberName(fc.Children()[0])
    30  
    31  	case *ast.CStyleCastExpr:
    32  		return getMemberName(fc.Children()[0])
    33  
    34  	}
    35  	return "", false
    36  }
    37  
    38  const undefineFunctionName string = "C4GO_UNDEFINE_NAME"
    39  
    40  func getName(p *program.Program, firstChild ast.Node) (name string, err error) {
    41  	switch fc := firstChild.(type) {
    42  	case *ast.DeclRefExpr:
    43  		return fc.Name, nil
    44  
    45  	case *ast.GenericSelectionExpr:
    46  		if len(fc.Children()) == 0 {
    47  			return undefineFunctionName, nil
    48  		}
    49  		return getName(p, fc.Children()[0])
    50  
    51  	case *ast.MemberExpr:
    52  		var expr goast.Expr
    53  		expr, _, _, _, err = transpileToExpr(fc, p, false)
    54  		if err != nil {
    55  			return
    56  		}
    57  		var buf bytes.Buffer
    58  		err = printer.Fprint(&buf, token.NewFileSet(), expr)
    59  		if err != nil {
    60  			return
    61  		}
    62  		return buf.String(), nil
    63  
    64  	case *ast.CallExpr:
    65  		if len(fc.Children()) == 0 {
    66  			return undefineFunctionName, nil
    67  		}
    68  		return getName(p, fc.Children()[0])
    69  
    70  	case *ast.ParenExpr:
    71  		if len(fc.Children()) == 0 {
    72  			return undefineFunctionName, nil
    73  		}
    74  		return getName(p, fc.Children()[0])
    75  
    76  	case *ast.UnaryOperator:
    77  		if len(fc.Children()) == 0 {
    78  			return undefineFunctionName, nil
    79  		}
    80  		return getName(p, fc.Children()[0])
    81  
    82  	case *ast.ImplicitCastExpr:
    83  		if len(fc.Children()) == 0 {
    84  			return undefineFunctionName, nil
    85  		}
    86  		return getName(p, fc.Children()[0])
    87  
    88  	case *ast.CStyleCastExpr:
    89  		if len(fc.Children()) == 0 {
    90  			return undefineFunctionName, nil
    91  		}
    92  		if fc.Kind == ast.CStyleCastExprNullToPointer {
    93  			// CallExpr 'void'
    94  			// `-ParenExpr 'void (*)(void)'
    95  			//   `-CStyleCastExpr 'void (*)(void)' <NullToPointer>
    96  			//     `-IntegerLiteral 'int' 0
    97  			return "nil", fmt.Errorf("no name for NullToPointer")
    98  		}
    99  		return getName(p, fc.Children()[0])
   100  
   101  	case *ast.ArraySubscriptExpr:
   102  		var expr goast.Expr
   103  		expr, _, _, _, err = transpileArraySubscriptExpr(fc, p)
   104  		if err != nil {
   105  			return
   106  		}
   107  		var buf bytes.Buffer
   108  		err = printer.Fprint(&buf, token.NewFileSet(), expr)
   109  		if err != nil {
   110  			return
   111  		}
   112  		return buf.String(), nil
   113  	}
   114  
   115  	return "", fmt.Errorf("cannot getName for: %#v", firstChild)
   116  }
   117  
   118  // simplificationCallExprPrintf - minimize Go code
   119  // transpile C code : printf("Hello")
   120  // to Go code       : fmt_Printf("Hello")
   121  // AST example :
   122  // CallExpr <> 'int'
   123  // |-ImplicitCastExpr <> 'int (*)(const char *, ...)' <FunctionToPointerDecay>
   124  // | `-DeclRefExpr <> 'int (const char *, ...)' Function 0x2fec178 'printf' 'int (const char *, ...)'
   125  // `-ImplicitCastExpr <> 'const char *' <BitCast>
   126  //
   127  //	`-ImplicitCastExpr <> 'char *' <ArrayToPointerDecay>
   128  //	  `-StringLiteral <> 'char [6]' lvalue "Hello"
   129  func simplificationCallExprPrintf(call *ast.CallExpr, p *program.Program) (
   130  	expr *goast.CallExpr, ok bool) {
   131  
   132  	var isPrintfCode bool
   133  	var printfText string
   134  	if call.Type == "int" && len(call.ChildNodes) == 2 {
   135  		var step1 bool
   136  		if impl, ok := call.ChildNodes[0].(*ast.ImplicitCastExpr); ok && len(impl.ChildNodes) == 1 {
   137  			if decl, ok := impl.ChildNodes[0].(*ast.DeclRefExpr); ok && decl.Name == "printf" {
   138  				if impl.Type == "int (*)(const char *, ...)" {
   139  					step1 = true
   140  				}
   141  			}
   142  		}
   143  		var step2 bool
   144  		if impl, ok := call.ChildNodes[1].(*ast.ImplicitCastExpr); ok {
   145  			if impl.Type == "const char *" && len(impl.ChildNodes) == 1 {
   146  				if impl2, ok := impl.ChildNodes[0].(*ast.ImplicitCastExpr); ok {
   147  					if impl2.Type == "char *" && len(impl2.ChildNodes) == 1 {
   148  						if str, ok := impl2.ChildNodes[0].(*ast.StringLiteral); ok {
   149  							step2 = true
   150  							printfText = str.Value
   151  						}
   152  					}
   153  				}
   154  			}
   155  		}
   156  		if step1 && step2 {
   157  			isPrintfCode = true
   158  		}
   159  	}
   160  
   161  	if !isPrintfCode {
   162  		return
   163  	}
   164  
   165  	// 0: *ast.ExprStmt {
   166  	// .  X: *ast.CallExpr {
   167  	// .  .  Fun: *ast.SelectorExpr {
   168  	// .  .  .  X: *ast.Ident {
   169  	// .  .  .  .  NamePos: 8:2
   170  	// .  .  .  .  Name: "fmt"
   171  	// .  .  .  }
   172  	// .  .  .  Sel: *ast.Ident {
   173  	// .  .  .  .  NamePos: 8:6
   174  	// .  .  .  .  Name: "Printf"
   175  	// .  .  .  }
   176  	// .  .  }
   177  	// .  .  Lparen: 8:12
   178  	// .  .  Args: []ast.Expr (len = 1) {
   179  	// .  .  .  0: *ast.BasicLit {
   180  	// .  .  .  .  ValuePos: 8:13
   181  	// .  .  .  .  Kind: STRING
   182  	// .  .  .  .  Value: "\"Hello, Golang\\n\""
   183  	// .  .  .  }
   184  	// .  .  }
   185  	// .  .  Ellipsis: -
   186  	// .  .  Rparen: 8:30
   187  	// .  }
   188  	// }
   189  	p.AddImport("fmt")
   190  	printfText = strconv.Quote(printfText)
   191  	return util.NewCallExpr("fmt"+"."+"Printf",
   192  		&goast.BasicLit{
   193  			Kind:  token.STRING,
   194  			Value: printfText,
   195  		}), true
   196  }
   197  
   198  // transpileCallExpr transpiles expressions that calls a function, for example:
   199  //
   200  //	foo("bar")
   201  //
   202  // It returns three arguments; the Go AST expression, the C type (that is
   203  // returned by the function) and any error. If there is an error returned you
   204  // can assume the first two arguments will not contain any useful information.
   205  func transpileCallExpr(n *ast.CallExpr, p *program.Program) (
   206  	expr *goast.CallExpr, resultType string,
   207  	preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   208  	defer func() {
   209  		if err != nil {
   210  			err = fmt.Errorf("error in transpileCallExpr : %v", err)
   211  		}
   212  		if resultType == "" {
   213  			resultType = n.Type
   214  		}
   215  	}()
   216  
   217  	functionName, err := getName(p, n)
   218  	if err != nil {
   219  		p.AddMessage(p.GenerateWarningMessage(err, n))
   220  		err = nil
   221  		functionName = undefineFunctionName
   222  	}
   223  	functionName = util.ConvertFunctionNameFromCtoGo(functionName)
   224  
   225  	defer func() {
   226  		if err != nil {
   227  			err = fmt.Errorf("name of call function is %v. %v",
   228  				functionName, err)
   229  		}
   230  	}()
   231  
   232  	// specific for va_list
   233  	changeVaListFuncs(&functionName)
   234  
   235  	// function "malloc" from stdlib.h
   236  	//
   237  	// Change from "malloc" to "calloc"
   238  	//
   239  	// CallExpr <> 'void *'
   240  	// |-ImplicitCastExpr <> 'void *(*)(unsigned long)' <FunctionToPointerDecay>
   241  	// | `-DeclRefExpr <> 'void *(unsigned long)' Function 'malloc' 'void *(unsigned long)'
   242  	// `-ImplicitCastExpr <> 'unsigned long' <IntegralCast>
   243  	//   `- ...
   244  	//
   245  	// CallExpr <> 'void *'
   246  	// |-ImplicitCastExpr <> 'void *(*)(unsigned long, unsigned long)' <FunctionToPointerDecay>
   247  	// | `-DeclRefExpr <> 'void *(unsigned long, unsigned long)' Function 'calloc' 'void *(unsigned long, unsigned long)'
   248  	// |-ImplicitCastExpr <> 'unsigned long' <IntegralCast>
   249  	// | `- ...
   250  	// `-UnaryExprOrTypeTraitExpr <> 'unsigned long' sizeof 'char'
   251  	if p.IncludeHeaderIsExists("stdlib.h") {
   252  		if functionName == "malloc" && len(n.Children()) == 2 {
   253  			// Change from "malloc" to "calloc"
   254  			unary, expression, back, err := findAndReplaceUnaryExprOrTypeTraitExpr(&n.Children()[1])
   255  			if err != nil {
   256  				back()
   257  				return transpileCallExprCalloc(n.Children()[1],
   258  					&ast.UnaryExprOrTypeTraitExpr{
   259  						Function: "sizeof",
   260  						Type1:    "unsigned long",
   261  						Type2:    "char",
   262  					}, p)
   263  			}
   264  			return transpileCallExprCalloc(expression, unary.(*ast.UnaryExprOrTypeTraitExpr), p)
   265  		}
   266  	}
   267  
   268  	if p.IncludeHeaderIsExists("stdio.h") &&
   269  		(functionName == "setbuf" || functionName == "setvbuf") {
   270  		// ignore function
   271  		return
   272  	}
   273  
   274  	// function "calloc" from stdlib.h
   275  	if p.IncludeHeaderIsExists("stdlib.h") {
   276  		if functionName == "calloc" && len(n.Children()) == 3 {
   277  			if unary, ok := n.Children()[2].(*ast.UnaryExprOrTypeTraitExpr); ok {
   278  				return transpileCallExprCalloc(n.Children()[1], unary, p)
   279  			}
   280  
   281  			call := &ast.CallExpr{}
   282  
   283  			call.AddChild(&ast.ImplicitCastExpr{
   284  				Type: "void *(*)(unsigned long)",
   285  			})
   286  			call.ChildNodes[0].(*ast.ImplicitCastExpr).AddChild(&ast.DeclRefExpr{
   287  				Type: "void *(unsigned long)",
   288  				Name: "malloc",
   289  			})
   290  
   291  			bin := &ast.BinaryOperator{
   292  				Operator: "*",
   293  				Type:     "unsigned long",
   294  			}
   295  			bin.AddChild(n.ChildNodes[1])
   296  			bin.AddChild(n.ChildNodes[2])
   297  			call.AddChild(bin)
   298  
   299  			return transpileCallExpr(call, p)
   300  		}
   301  	}
   302  
   303  	// function "qsort" from stdlib.h
   304  	if p.IncludeHeaderIsExists("stdlib.h") {
   305  		if functionName == "qsort" && len(n.Children()) == 5 {
   306  			return transpileCallExprQsort(n, p)
   307  		}
   308  	}
   309  
   310  	// function "bsearch" from stdlib.h
   311  	if p.IncludeHeaderIsExists("stdlib.h") {
   312  		if functionName == "bsearch" && len(n.Children()) == 6 {
   313  			return transpileCallExprBsearch(n, p)
   314  		}
   315  	}
   316  
   317  	// function "printf" from stdio.h simplification
   318  	if p.IncludeHeaderIsExists("stdio.h") {
   319  		if functionName == "printf" && len(n.Children()) == 2 {
   320  			if e, ok := simplificationCallExprPrintf(n, p); ok {
   321  				return e, "int", nil, nil, nil
   322  			}
   323  		}
   324  	}
   325  
   326  	// Get the function definition from it's name. The case where it is not
   327  	// defined is handled below (we haven't seen the prototype yet).
   328  	functionDef := p.GetFunctionDefinition(functionName)
   329  
   330  	if functionDef != nil {
   331  		p.SetCalled(functionName)
   332  	}
   333  
   334  	if functionDef == nil {
   335  		// We do not have a prototype for the function, but we should not exit
   336  		// here. Instead we will create a mock definition for it so that this
   337  		// transpile function will always return something and continue.
   338  		//
   339  		// The mock function definition is never actually saved to the program
   340  		// definitions, so each time we see the CallExpr it will run this every
   341  		// time. This is so if we come across the real prototype later it will
   342  		// be handled correctly. Or at least "more" correctly.
   343  		functionDef = &program.DefinitionFunction{
   344  			Name: functionName,
   345  		}
   346  		if len(n.Children()) > 0 {
   347  
   348  			checker := func(t string) bool {
   349  				return util.IsFunction(t) || types.IsTypedefFunction(p, t)
   350  			}
   351  
   352  			var finder func(n ast.Node) string
   353  			finder = func(n ast.Node) (t string) {
   354  				switch v := n.(type) {
   355  				case *ast.ImplicitCastExpr:
   356  					t = v.Type
   357  				case *ast.ParenExpr:
   358  					t = v.Type
   359  				case *ast.CStyleCastExpr:
   360  					t = v.Type
   361  				default:
   362  					panic(fmt.Errorf("add type %T", n))
   363  				}
   364  				if checker(t) {
   365  					return t
   366  				}
   367  				if len(n.Children()) == 0 {
   368  					return ""
   369  				}
   370  				return finder(n.Children()[0])
   371  			}
   372  
   373  			if t := finder(n.Children()[0]); checker(t) {
   374  				if v, ok := p.TypedefType[t]; ok {
   375  					t = v
   376  				} else {
   377  					if types.IsTypedefFunction(p, t) {
   378  						t = t[0 : len(t)-len(" *")]
   379  						t = p.TypedefType[t]
   380  					}
   381  				}
   382  				prefix, _, fields, returns, err := util.ParseFunction(t)
   383  				if err != nil {
   384  					p.AddMessage(p.GenerateWarningMessage(fmt.Errorf(
   385  						"cannot resolve function : %v", err), n))
   386  					return nil, "", nil, nil, err
   387  				}
   388  				if len(prefix) != 0 {
   389  					p.AddMessage(p.GenerateWarningMessage(fmt.Errorf(
   390  						"prefix `%v` is not used in type : %v",
   391  						prefix, t), n))
   392  				}
   393  				functionDef.ReturnType = returns[0]
   394  				functionDef.ArgumentTypes = fields
   395  			}
   396  		}
   397  	} else {
   398  
   399  		// type correction for definition function in
   400  		// package program
   401  		var ok bool
   402  		for pos, arg := range n.Children() {
   403  			if pos == 0 {
   404  				continue
   405  			}
   406  			if pos >= len(functionDef.ArgumentTypes) {
   407  				continue
   408  			}
   409  			if arg, ok = arg.(*ast.ImplicitCastExpr); ok {
   410  				arg.(*ast.ImplicitCastExpr).Type = functionDef.ArgumentTypes[pos-1]
   411  			}
   412  		}
   413  	}
   414  
   415  	if functionDef.Substitution != "" {
   416  		parts := strings.Split(functionDef.Substitution, ".")
   417  		importName := strings.Join(parts[:len(parts)-1], ".")
   418  		p.AddImport(importName)
   419  
   420  		parts2 := strings.Split(functionDef.Substitution, "/")
   421  		functionName = parts2[len(parts2)-1]
   422  	}
   423  
   424  	args := []goast.Expr{}
   425  	argTypes := []string{}
   426  	i := 0
   427  	for _, arg := range n.Children()[1:] {
   428  		if bin, ok := arg.(*ast.BinaryOperator); ok && bin.Operator == "=" {
   429  			// example :
   430  			// from :
   431  			// call(val = 43);
   432  			// to:
   433  			// call(val = 43,val);
   434  			var b ast.BinaryOperator
   435  			b.Type = bin.Type
   436  			b.Operator = ","
   437  			b.AddChild(arg)
   438  			b.AddChild(bin.Children()[0])
   439  			arg = &b
   440  		}
   441  		if cmp, ok := arg.(*ast.CompoundAssignOperator); ok {
   442  			// example :
   443  			// from :
   444  			// call(val += 43);
   445  			// to:
   446  			// call(val += 43,val);
   447  			var b ast.BinaryOperator
   448  			b.Type = cmp.Type
   449  			b.Operator = ","
   450  			b.AddChild(arg)
   451  			b.AddChild(cmp.Children()[0])
   452  			arg = &b
   453  		}
   454  		e, eType, newPre, newPost, err := atomicOperation(arg, p)
   455  		if err != nil {
   456  			err = fmt.Errorf("argument position is %d. %v", i, err)
   457  			p.AddMessage(p.GenerateWarningMessage(err, arg))
   458  			return nil, "unknown2", nil, nil, err
   459  		}
   460  		argTypes = append(argTypes, eType)
   461  		preStmts, postStmts = combinePreAndPostStmts(
   462  			preStmts, postStmts, newPre, newPost)
   463  
   464  		args = append(args, e)
   465  		i++
   466  	}
   467  
   468  	// These are the arguments once any transformations have taken place.
   469  	realArgs := []goast.Expr{}
   470  
   471  	// Apply transformation if needed. A transformation rearranges the return
   472  	// value(s) and parameters. It is also used to indicate when a variable must
   473  	// be passed by reference.
   474  	if functionDef.ReturnParameters != nil || functionDef.Parameters != nil {
   475  		for i, a := range functionDef.Parameters {
   476  			byReference := false
   477  
   478  			// Negative position means that it must be passed by reference.
   479  			if a < 0 {
   480  				byReference = true
   481  				a = -a
   482  			}
   483  
   484  			// Rearrange the arguments. The -1 is because 0 would be the return
   485  			// value.
   486  			realArg := args[a-1]
   487  
   488  			if byReference {
   489  				// We have to create a temporary variable to pass by reference.
   490  				// Then we can assign the real variable from it.
   491  				realArg = &goast.UnaryExpr{
   492  					Op: token.AND,
   493  					X:  args[i],
   494  				}
   495  			} else {
   496  				realArg, err = types.CastExpr(p, realArg, argTypes[i],
   497  					functionDef.ArgumentTypes[i])
   498  				p.AddMessage(p.GenerateWarningMessage(err, n))
   499  
   500  				if realArg == nil {
   501  					realArg = util.NewNil()
   502  				}
   503  			}
   504  
   505  			if realArg == nil {
   506  				return nil, "", preStmts, postStmts,
   507  					fmt.Errorf("real argument is nil in function : %s", functionName)
   508  			}
   509  
   510  			realArgs = append(realArgs, realArg)
   511  		}
   512  	} else {
   513  		// Keep all the arguments the same. But make sure we cast to the correct
   514  		// types.
   515  		// Example of functionDef.ArgumentTypes :
   516  		// [void *, int]
   517  		// [char *, char * , ...]
   518  		// Example of args:
   519  		// [void *, int]
   520  		// [char *, char *, char *, int, double]
   521  		//
   522  		for i, a := range args {
   523  			realType := "unknownType"
   524  			if i < len(functionDef.ArgumentTypes) {
   525  				if len(functionDef.ArgumentTypes) > 1 &&
   526  					i >= len(functionDef.ArgumentTypes)-1 &&
   527  					functionDef.ArgumentTypes[len(functionDef.ArgumentTypes)-1] == "..." {
   528  					realType = functionDef.ArgumentTypes[len(functionDef.ArgumentTypes)-2]
   529  				} else {
   530  					if len(functionDef.ArgumentTypes) > 0 {
   531  						if len(functionDef.ArgumentTypes[i]) != 0 {
   532  							realType = functionDef.ArgumentTypes[i]
   533  							if strings.TrimSpace(realType) != "void" {
   534  								a, err = types.CastExpr(p, a, argTypes[i], realType)
   535  
   536  								if p.AddMessage(p.GenerateWarningMessage(err, n)) {
   537  									a = util.NewNil()
   538  								}
   539  							}
   540  						}
   541  					}
   542  				}
   543  			}
   544  
   545  			if strings.Contains(realType, "...") {
   546  				p.AddMessage(p.GenerateWarningMessage(
   547  					fmt.Errorf("not acceptable type '...'"), n))
   548  			}
   549  
   550  			if a == nil {
   551  				return nil, "", preStmts, postStmts,
   552  					fmt.Errorf("argument is nil in function : %s", functionName)
   553  			}
   554  
   555  			if len(functionDef.ArgumentTypes) > i {
   556  				if !types.IsPointer(functionDef.ArgumentTypes[i], p) {
   557  					if strings.HasPrefix(functionDef.ArgumentTypes[i], "union ") {
   558  						a = &goast.CallExpr{
   559  							Fun: &goast.SelectorExpr{
   560  								X:   a,
   561  								Sel: goast.NewIdent("copy"),
   562  							},
   563  							Lparen: 1,
   564  						}
   565  					}
   566  				}
   567  			}
   568  
   569  			realArgs = append(realArgs, a)
   570  		}
   571  	}
   572  
   573  	// Added for support removing function `free` of <stdlib.h>
   574  	// Example of C code:
   575  	// free(i+=4,buffer)
   576  	// Example of result Go code:
   577  	// i += 4
   578  	// _ = buffer
   579  	if functionDef.Substitution == "_" {
   580  		devNull := &goast.AssignStmt{
   581  			Lhs: []goast.Expr{goast.NewIdent("_")},
   582  			Tok: token.ASSIGN,
   583  			Rhs: []goast.Expr{realArgs[0]},
   584  		}
   585  		preStmts = append(preStmts, devNull)
   586  		return nil, n.Type, preStmts, postStmts, nil
   587  	}
   588  
   589  	return util.NewCallExpr(functionName, realArgs...),
   590  		functionDef.ReturnType, preStmts, postStmts, nil
   591  }
   592  
   593  func findAndReplaceUnaryExprOrTypeTraitExpr(node *ast.Node) (
   594  	unary ast.Node, tree ast.Node, back func(), err error) {
   595  
   596  	defer func() {
   597  		if err != nil {
   598  			err = fmt.Errorf("cannot findAndReplaceUnaryExprOrTypeTraitExpr: err = %v", err)
   599  			if (*node) != nil {
   600  				err = fmt.Errorf("code line: %d. %v", (*node).Position().Line, err)
   601  			}
   602  		}
   603  	}()
   604  
   605  	var counter int
   606  	var lastNode *ast.Node
   607  	one := &ast.IntegerLiteral{Type: "int", Value: "1"}
   608  
   609  	var searcher func(*ast.Node) bool
   610  	replacer := func(node *ast.Node) {
   611  		unary = *node
   612  		lastNode = node
   613  		*node = one
   614  		counter++
   615  	}
   616  	searcher = func(node *ast.Node) (modify bool) {
   617  		// find
   618  		if u, ok := (*node).(*ast.UnaryExprOrTypeTraitExpr); ok &&
   619  			u.Function == "sizeof" {
   620  			return true
   621  		}
   622  		for i := range (*node).Children() {
   623  			if searcher(&((*node).Children()[i])) {
   624  				replacer(&((*node).Children()[i]))
   625  			}
   626  		}
   627  		return false
   628  	}
   629  	if searcher(node) {
   630  		unary = *node
   631  		lastNode = node
   632  		*node = one
   633  		counter++
   634  	}
   635  
   636  	back = func() {
   637  		// return back node
   638  		if unary != nil {
   639  			*lastNode = unary
   640  		}
   641  	}
   642  
   643  	if counter != 1 {
   644  		err = fmt.Errorf("counter is not 1: %d", counter)
   645  		return
   646  	}
   647  	if unary == nil {
   648  		err = fmt.Errorf("pointer is nil")
   649  		return
   650  	}
   651  
   652  	tree = *node
   653  
   654  	return
   655  }
   656  
   657  // calloc nodes:
   658  // [0] - function identification
   659  // [1] - expression
   660  // [2] - type UnaryExprOrTypeTraitExpr always
   661  func transpileCallExprCalloc(expression ast.Node, unary *ast.UnaryExprOrTypeTraitExpr, p *program.Program) (
   662  	expr *goast.CallExpr, resultType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   663  	defer func() {
   664  		if err != nil {
   665  			err = fmt.Errorf("function: calloc. err = %v", err)
   666  		}
   667  	}()
   668  
   669  	size, _, newPre, newPost, err := atomicOperation(expression, p)
   670  	if err != nil {
   671  		return
   672  	}
   673  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   674  
   675  	var t string = unary.Type2
   676  	if t == "" {
   677  		_, t, _, _, _ = transpileToExpr(unary, p, false)
   678  	}
   679  	resultType = t + "*"
   680  	t, err = types.ResolveType(p, t)
   681  	if err != nil {
   682  		return nil, "", nil, nil, err
   683  	}
   684  	goType := &goast.ArrayType{Elt: goast.NewIdent(t)}
   685  
   686  	return util.NewCallExpr("make", goType, size),
   687  		resultType, preStmts, postStmts, nil
   688  }
   689  
   690  func transpileCallExprQsort(n *ast.CallExpr, p *program.Program) (
   691  	expr *goast.CallExpr, resultType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   692  	defer func() {
   693  		if err != nil {
   694  			err = fmt.Errorf("function: qsort. err = %v", err)
   695  		}
   696  		if resultType == "" {
   697  			resultType = n.Type
   698  		}
   699  	}()
   700  	// CallExpr 0x2c6b1b0 'void'
   701  	// |-ImplicitCastExpr 'void (*)(void *, size_t, size_t, __compar_fn_t)' <FunctionToPointerDecay>
   702  	// | `-DeclRefExpr 'void (void *, size_t, size_t, __compar_fn_t)' Function 0x2bec110 'qsort' 'void (void *, size_t, size_t, __compar_fn_t)'
   703  	// |-ImplicitCastExpr 'void *' <BitCast>
   704  	// | `-ImplicitCastExpr 'int *' <ArrayToPointerDecay>
   705  	// |   `-DeclRefExpr 'int [6]' lvalue Var 0x2c6a6c0 'values' 'int [6]'
   706  	// |-ImplicitCastExpr 'size_t':'unsigned long' <IntegralCast>
   707  	// | `-IntegerLiteral 'int' 6
   708  	// |-UnaryExprOrTypeTraitExpr 'unsigned long' sizeof 'int'
   709  	// `-ImplicitCastExpr 'int (*)(const void *, const void *)' <FunctionToPointerDecay>
   710  	//   `-DeclRefExpr 'int (const void *, const void *)' Function 0x2c6aa70 'compare' 'int (const void *, const void *)'
   711  	//
   712  	// CallExpr  'void'
   713  	// |-ImplicitCastExpr 'void (*)(void *, size_t, size_t, __compar_fn_t)' <FunctionToPointerDecay>
   714  	// | `-DeclRefExpr 'void (void *, size_t, size_t, __compar_fn_t)' Function 0x361b6d0 'qsort' 'void (void *, size_t, size_t, __compar_fn_t)'
   715  	// |-ImplicitCastExpr 'void *' <BitCast>
   716  	// | `-ImplicitCastExpr 'int *' <LValueToRValue>
   717  	// |   `-DeclRefExpr 'int *' lvalue ParmVar 0x3668088 'id' 'int *'
   718  	// |-ImplicitCastExpr 'size_t':'unsigned long' <IntegralCast>
   719  	// | `-ImplicitCastExpr 'int' <LValueToRValue>
   720  	// |   `-DeclRefExpr 'int' lvalue Var 0x36684e0 'nid' 'int'
   721  	// |-UnaryExprOrTypeTraitExpr 'unsigned long' sizeof
   722  	// | `-ParenExpr 'int' lvalue
   723  	// |   `-ArraySubscriptExpr 'int' lvalue
   724  	// |     |-ImplicitCastExpr 'int *' <LValueToRValue>
   725  	// |     | `-DeclRefExpr  'int *' lvalue ParmVar 0x3668088 'id' 'int *'
   726  	// |     `-IntegerLiteral 'int' 0
   727  	// `-ImplicitCastExpr '__compar_fn_t':'int (*)(const void *, const void *)' <BitCast>
   728  	//   `-CStyleCastExpr 'void *' <BitCast>
   729  	//     `-ImplicitCastExpr 'int (*)(void *, void *)' <FunctionToPointerDecay>
   730  	//       `-DeclRefExpr 'int (void *, void *)' Function 0x3665148 'intcmp' 'int (void *, void *)'
   731  	//
   732  
   733  	arr, _, newPre, newPost, err := atomicOperation(n.Children()[1], p)
   734  	if err != nil {
   735  		err = fmt.Errorf("cannot transpile array node: %v", err)
   736  		return nil, "", nil, nil, err
   737  	}
   738  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   739  
   740  	t, ok := ast.GetTypeIfExist(n.Children()[1].Children()[0])
   741  	if !ok {
   742  		err = fmt.Errorf("cannot take type array node")
   743  		return nil, "", nil, nil, err
   744  	}
   745  
   746  	*t = strings.Replace(*t, "*", "", 1)
   747  
   748  	arrType, err := types.ResolveType(p, *t)
   749  	if err != nil {
   750  		err = fmt.Errorf("cannot resolve array type: %v", err)
   751  		return nil, "", nil, nil, err
   752  	}
   753  
   754  	size, sizeType, newPre, newPost, err := atomicOperation(n.Children()[2], p)
   755  	if err != nil {
   756  		err = fmt.Errorf("cannot transpile size node: %v", err)
   757  		return nil, "", nil, nil, err
   758  	}
   759  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   760  
   761  	size, err = types.CastExpr(p, size, sizeType, "int")
   762  	if err != nil {
   763  		err = fmt.Errorf("cannot cast size node to int : %v", err)
   764  		return nil, "", nil, nil, err
   765  	}
   766  
   767  	f, _, newPre, newPost, err := atomicOperation(n.Children()[4], p)
   768  	if err != nil {
   769  		err = fmt.Errorf("cannot transpile function node: %v", err)
   770  		return nil, "", nil, nil, err
   771  	}
   772  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   773  
   774  	// cast from `int (void *, void *)` to `bool (int, int)`
   775  
   776  	valA := CreateSliceFromReference(arrType, &goast.IndexExpr{
   777  		X:      arr,
   778  		Lbrack: 1,
   779  		Index:  goast.NewIdent("a"),
   780  	})
   781  	valB := CreateSliceFromReference(arrType, &goast.IndexExpr{
   782  		X:      arr,
   783  		Lbrack: 1,
   784  		Index:  goast.NewIdent("b"),
   785  	})
   786  	f = &goast.FuncLit{
   787  		Type: &goast.FuncType{
   788  			Params: &goast.FieldList{
   789  				List: []*goast.Field{
   790  					{
   791  						Names: []*goast.Ident{goast.NewIdent("a"), goast.NewIdent("b")},
   792  						Type:  goast.NewIdent("int"),
   793  					},
   794  				},
   795  			},
   796  			Results: &goast.FieldList{
   797  				List: []*goast.Field{
   798  					{Type: goast.NewIdent("bool")},
   799  				},
   800  			},
   801  		},
   802  		Body: &goast.BlockStmt{
   803  			List: []goast.Stmt{
   804  				&goast.ReturnStmt{
   805  					Results: []goast.Expr{
   806  						&goast.BinaryExpr{
   807  							X: &goast.CallExpr{
   808  								Fun: f,
   809  								Args: []goast.Expr{
   810  									valA,
   811  									valB,
   812  								},
   813  							},
   814  							Op: token.LEQ, // <=
   815  							Y:  goast.NewIdent("0"),
   816  						},
   817  					},
   818  				},
   819  			},
   820  		},
   821  	}
   822  
   823  	p.AddImport("sort")
   824  
   825  	return util.NewCallExpr("sort.SliceStable",
   826  		&goast.SliceExpr{
   827  			X:    arr,
   828  			High: size,
   829  		},
   830  		f,
   831  	), "", preStmts, postStmts, nil
   832  
   833  }
   834  
   835  func transpileCallExprBsearch(n *ast.CallExpr, p *program.Program) (
   836  	expr *goast.CallExpr, resultType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   837  	defer func() {
   838  		if err != nil {
   839  			err = fmt.Errorf("function: bsearch. err = %v", err)
   840  		}
   841  		if resultType == "" {
   842  			resultType = n.Type
   843  		}
   844  	}()
   845  
   846  	key, _, newPre, newPost, err := atomicOperation(n.Children()[1], p)
   847  	if err != nil {
   848  		err = fmt.Errorf("cannot transpile key node: %v", err)
   849  		return nil, "", nil, nil, err
   850  	}
   851  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   852  
   853  	arr, _, newPre, newPost, err := atomicOperation(n.Children()[2], p)
   854  	if err != nil {
   855  		err = fmt.Errorf("cannot transpile array node: %v", err)
   856  		return nil, "", nil, nil, err
   857  	}
   858  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   859  
   860  	t, ok := ast.GetTypeIfExist(n.Children()[2].Children()[0])
   861  	if !ok {
   862  		err = fmt.Errorf("cannot take type array node")
   863  		return nil, "", nil, nil, err
   864  	}
   865  
   866  	*t = strings.Replace(*t, "*", "", 1)
   867  
   868  	arrType, err := types.ResolveType(p, *t)
   869  	if err != nil {
   870  		err = fmt.Errorf("cannot resolve array type: %v", err)
   871  		return nil, "", nil, nil, err
   872  	}
   873  
   874  	size, sizeType, newPre, newPost, err := atomicOperation(n.Children()[3], p)
   875  	if err != nil {
   876  		err = fmt.Errorf("cannot transpile size node: %v", err)
   877  		return nil, "", nil, nil, err
   878  	}
   879  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   880  
   881  	size, err = types.CastExpr(p, size, sizeType, "int")
   882  	if err != nil {
   883  		err = fmt.Errorf("cannot cast size node to int : %v", err)
   884  		return nil, "", nil, nil, err
   885  	}
   886  
   887  	f, _, newPre, newPost, err := atomicOperation(n.Children()[5], p)
   888  	if err != nil {
   889  		err = fmt.Errorf("cannot transpile function node: %v", err)
   890  		return nil, "", nil, nil, err
   891  	}
   892  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   893  
   894  	// cast from `int (void *, void *)` to `bool (int, int)`
   895  
   896  	// TODO: Generate missing handle
   897  	p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("TODO: missing second variable to handle nil cast interface{}"), n))
   898  
   899  	val := CreateSliceFromReference(arrType, &goast.IndexExpr{
   900  		X:      arr,
   901  		Lbrack: 1,
   902  		Index:  goast.NewIdent("a"),
   903  	})
   904  	res := CreateSliceFromReference(arrType, &goast.IndexExpr{
   905  		X:      arr,
   906  		Lbrack: 1,
   907  		Index:  goast.NewIdent("index"),
   908  	})
   909  
   910  	f = &goast.FuncLit{
   911  		Type: &goast.FuncType{
   912  			Params: &goast.FieldList{
   913  				List: []*goast.Field{
   914  					{
   915  						Names: []*goast.Ident{goast.NewIdent("a")},
   916  						Type:  goast.NewIdent("int"),
   917  					},
   918  				},
   919  			},
   920  			Results: &goast.FieldList{
   921  				List: []*goast.Field{
   922  					{Type: goast.NewIdent("int")},
   923  				},
   924  			},
   925  		},
   926  		Body: &goast.BlockStmt{
   927  			List: []goast.Stmt{
   928  				&goast.ReturnStmt{
   929  					Results: []goast.Expr{
   930  						&goast.CallExpr{
   931  							Fun: goast.NewIdent("int"),
   932  							Args: []goast.Expr{
   933  								&goast.CallExpr{
   934  									Fun: f,
   935  									Args: []goast.Expr{
   936  										val,
   937  										goast.Expr(key),
   938  									},
   939  								},
   940  							},
   941  						},
   942  					},
   943  				},
   944  			},
   945  		},
   946  	}
   947  
   948  	fGetIndex := &goast.FuncLit{
   949  		Type: &goast.FuncType{
   950  			Params: &goast.FieldList{
   951  				List: []*goast.Field{
   952  					{
   953  						Names: []*goast.Ident{goast.NewIdent("index")},
   954  						Type:  goast.NewIdent("int"),
   955  					},
   956  				},
   957  			},
   958  			Results: &goast.FieldList{
   959  				List: []*goast.Field{
   960  					{Type: goast.NewIdent("interface{}")},
   961  				},
   962  			},
   963  		},
   964  		Body: &goast.BlockStmt{
   965  			List: []goast.Stmt{
   966  				&goast.ReturnStmt{
   967  					Results: []goast.Expr{
   968  						res,
   969  					},
   970  				},
   971  			},
   972  		},
   973  	}
   974  
   975  	p.AddImport("github.com/Konstantin8105/c4go/noarch")
   976  
   977  	return util.NewCallExpr("noarch.BSearch",
   978  		// sort.Search expecting a "int" type
   979  		&goast.CallExpr{
   980  			Fun:  goast.NewIdent("int"),
   981  			Args: []goast.Expr{size},
   982  		},
   983  		f,
   984  		fGetIndex,
   985  	), "", preStmts, postStmts, nil
   986  
   987  }