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

     1  // This file contains functions for transpiling common branching and control
     2  // flow, such as "if", "while", "do" and "for". The more complicated control
     3  // flows like "switch" will be put into their own file of the same or sensible
     4  // name.
     5  
     6  package transpiler
     7  
     8  import (
     9  	"fmt"
    10  	"go/token"
    11  
    12  	"github.com/Konstantin8105/c4go/ast"
    13  	"github.com/Konstantin8105/c4go/program"
    14  	"github.com/Konstantin8105/c4go/types"
    15  	"github.com/Konstantin8105/c4go/util"
    16  
    17  	goast "go/ast"
    18  )
    19  
    20  func transpileIfStmt(n *ast.IfStmt, p *program.Program) (
    21  	_ *goast.IfStmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
    22  
    23  	defer func() {
    24  		if err != nil {
    25  			err = fmt.Errorf("cannot transpileIfStmt. %v", err)
    26  		}
    27  	}()
    28  
    29  	children := n.Children()
    30  
    31  	// There is always 4 or 5 children in an IfStmt. For example:
    32  	//
    33  	//     if (i == 0) {
    34  	//         return 0;
    35  	//     } else {
    36  	//         return 1;
    37  	//     }
    38  	//
    39  	// 1. Not sure what this is for. This gets removed.
    40  	// 2. Not sure what this is for.
    41  	// 3. conditional = BinaryOperator: i == 0
    42  	// 4. body = CompoundStmt: { return 0; }
    43  	// 5. elseBody = CompoundStmt: { return 1; }
    44  	//
    45  	// elseBody will be nil if there is no else clause.
    46  
    47  	// On linux I have seen only 4 children for an IfStmt with the same
    48  	// definitions above, but missing the first argument. Since we don't
    49  	// know what the first argument is for anyway we will just remove it on
    50  	// Mac if necessary.
    51  	if len(children) == 5 && children[0] != nil {
    52  		panic("non-nil child 0 in IfStmt")
    53  	}
    54  	if len(children) == 5 {
    55  		children = children[1:]
    56  	}
    57  
    58  	// From here on there must be 4 children.
    59  	if len(children) != 4 {
    60  		children = append([]ast.Node{nil}, children...)
    61  	}
    62  	if len(children) != 4 {
    63  		children = append(children, nil)
    64  	}
    65  
    66  	// Maybe we will discover what the nil value is?
    67  	if children[0] != nil {
    68  		panic("non-nil child 0 in IfStmt")
    69  	}
    70  
    71  	// The last parameter must be false because we are transpiling an
    72  	// expression - assignment operators need to be wrapped in closures.
    73  	conditional, conditionalType, newPre, newPost, err := atomicOperation(children[1], p)
    74  	if err != nil {
    75  		err = fmt.Errorf("cannot transpile for condition. %v", err)
    76  		return nil, nil, nil, err
    77  	}
    78  	// null in C is false
    79  	if conditionalType == types.NullPointer {
    80  		conditional = util.NewIdent("false")
    81  		conditionalType = "bool"
    82  	}
    83  
    84  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
    85  
    86  	// The condition in Go must always be a bool.
    87  	boolCondition, err := types.CastExpr(p, conditional, conditionalType, "bool")
    88  	p.AddMessage(p.GenerateWarningMessage(err, n))
    89  
    90  	if boolCondition == nil {
    91  		boolCondition = util.NewNil()
    92  	}
    93  
    94  	body := new(goast.BlockStmt)
    95  
    96  	if children[2] != nil {
    97  		var newPre, newPost []goast.Stmt
    98  		body, newPre, newPost, err = transpileToBlockStmt(children[2], p)
    99  		if err != nil {
   100  			return nil, nil, nil, err
   101  		}
   102  
   103  		preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   104  		if body == nil {
   105  			return nil, nil, nil, fmt.Errorf("body of If cannot by nil")
   106  		}
   107  	}
   108  
   109  	if boolCondition == nil {
   110  		return nil, nil, nil, fmt.Errorf("bool Condition in If cannot by nil")
   111  	}
   112  	r := &goast.IfStmt{
   113  		Cond: boolCondition,
   114  		Body: body,
   115  	}
   116  
   117  	if children[3] != nil {
   118  		elseBody, newPre, newPost, err := transpileToBlockStmt(children[3], p)
   119  		if err != nil {
   120  			return nil, nil, nil, err
   121  		}
   122  
   123  		preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   124  
   125  		if elseBody != nil {
   126  			r.Else = elseBody
   127  			if _, ok := children[3].(*ast.IfStmt); ok {
   128  				if len(elseBody.List) == 1 {
   129  					r.Else = elseBody.List[0]
   130  				}
   131  			}
   132  		} else {
   133  			return nil, nil, nil, fmt.Errorf("body of Else in If cannot be nil")
   134  		}
   135  	}
   136  
   137  	return r, preStmts, postStmts, nil
   138  }
   139  
   140  func transpileForStmt(n *ast.ForStmt, p *program.Program) (
   141  	f goast.Stmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   142  
   143  	// This `defer` is workaround
   144  	// Please remove after solving all problems
   145  	defer func() {
   146  		if err != nil {
   147  			err = fmt.Errorf("cannot transpile ForStmt: err = %v", err)
   148  			p.AddMessage(p.GenerateWarningMessage(err, n))
   149  		}
   150  	}()
   151  
   152  	children := n.Children()
   153  
   154  	// There are always 5 children in a ForStmt, for example:
   155  	//
   156  	//     for ( c = 0 ; c < n ; c++ ) {
   157  	//         doSomething();
   158  	//     }
   159  	//
   160  	// 1. initExpression = BinaryStmt: c = 0
   161  	// 2. Not sure what this is for, but it's always nil. There is a panic
   162  	//    below in case we discover what it is used for (pun intended).
   163  	// 3. conditionalExpression = BinaryStmt: c < n
   164  	// 4. stepExpression = BinaryStmt: c++
   165  	// 5. body = CompoundStmt: { CallExpr }
   166  
   167  	if len(children) != 5 {
   168  		panic(fmt.Sprintf("Expected 5 children in ForStmt, got %#v", children))
   169  	}
   170  
   171  	// TODO: The second child of a ForStmt appears to always be null.
   172  	// Are there any cases where it is used?
   173  	if children[1] != nil {
   174  		panic("non-nil child 1 in ForStmt")
   175  	}
   176  
   177  	switch c := children[0].(type) {
   178  	case *ast.BinaryOperator:
   179  		if c.Operator == "," {
   180  			// If we have 2 and more initializations like
   181  			// in operator for
   182  			// for( a = 0, b = 0, c = 0; a < 5; a ++)
   183  			// recursive action to code like that:
   184  			// a = 0;
   185  			// b = 0;
   186  			// for(c = 0 ; a < 5 ; a++)
   187  			before, newPre, newPost, err := transpileToStmt(children[0], p)
   188  			if err != nil {
   189  				err = fmt.Errorf("cannot transpile comma binaryoperator. %v",
   190  					err)
   191  				return nil, nil, nil, err
   192  			}
   193  			preStmts = append(preStmts, combineStmts(newPre, before, newPost)...)
   194  			children[0] = c.Children()[1]
   195  		}
   196  	case *ast.DeclStmt:
   197  		{
   198  			// If we have 2 and more initializations like
   199  			// in operator for
   200  			// for(int a = 0, b = 0, c = 0; a < 5; a ++)
   201  			newPre, err := transpileToStmts(children[0], p)
   202  			if err != nil {
   203  				err = fmt.Errorf("cannot transpile with many initialization. %v",
   204  					err)
   205  				return nil, nil, nil, err
   206  			}
   207  			children[0] = nil
   208  			preStmts = append(preStmts, newPre...)
   209  		}
   210  	}
   211  
   212  	init, newPre, newPost, err := transpileToStmt(children[0], p)
   213  	if err != nil {
   214  		err = fmt.Errorf("cannot init. %v", err)
   215  		return nil, nil, nil, err
   216  	}
   217  
   218  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   219  
   220  	// If we have 2 and more increments
   221  	// in operator for
   222  	// for( a = 0; a < 5; a ++, b++, c+=2)
   223  	switch c := children[3].(type) {
   224  	case *ast.BinaryOperator:
   225  		if c.Operator == "," {
   226  			// recursive action to code like that:
   227  			// a = 0;
   228  			// b = 0;
   229  			// for(a = 0 ; a < 5 ; ){
   230  			// 		body
   231  			// 		a++;
   232  			// 		b++;
   233  			//		c+=2;
   234  			// }
   235  			//
   236  			var compound *ast.CompoundStmt
   237  			if children[4] != nil {
   238  				// if body is exist
   239  				if _, ok := children[4].(*ast.CompoundStmt); !ok {
   240  					compound = new(ast.CompoundStmt)
   241  					compound.AddChild(children[4])
   242  				} else {
   243  					compound = children[4].(*ast.CompoundStmt)
   244  				}
   245  			} else {
   246  				// if body is not exist
   247  				compound = new(ast.CompoundStmt)
   248  			}
   249  			compound.ChildNodes = append(
   250  				compound.Children(),
   251  				c.Children()[0:len(c.Children())]...)
   252  			children[4] = compound
   253  			children[3] = nil
   254  		}
   255  	}
   256  
   257  	var post goast.Stmt
   258  	var transpilate bool
   259  	if v, ok := children[3].(*ast.UnaryOperator); ok {
   260  		if vv, ok := v.Children()[0].(*ast.DeclRefExpr); ok {
   261  			if !types.IsPointer(vv.Type, p) && !util.IsFunction(vv.Type) {
   262  				switch v.Operator {
   263  				case "++":
   264  					// for case:
   265  					// for(...;...;i++)...
   266  					post = &goast.IncDecStmt{
   267  						X:   util.NewIdent(vv.Name),
   268  						Tok: token.INC,
   269  					}
   270  					transpilate = true
   271  				case "--":
   272  					// for case:
   273  					// for(...;...;i--)...
   274  					post = &goast.IncDecStmt{
   275  						X:   util.NewIdent(vv.Name),
   276  						Tok: token.DEC,
   277  					}
   278  					transpilate = true
   279  				}
   280  			}
   281  		}
   282  	}
   283  	if !transpilate {
   284  		post, newPre, newPost, err = transpileToStmt(children[3], p)
   285  		if err != nil {
   286  			err = fmt.Errorf("cannot transpile children[3] : %v", err)
   287  			return nil, nil, nil, err
   288  		}
   289  
   290  		preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   291  	}
   292  
   293  	// If we have 2 and more conditions
   294  	// in operator for
   295  	// for( a = 0; b = c, b++, a < 5; a ++)
   296  	switch c := children[2].(type) {
   297  	case *ast.BinaryOperator:
   298  		if c.Operator == "," {
   299  			// recursive action to code like that:
   300  			// a = 0;
   301  			// b = 0;
   302  			// for(a = 0 ; ; c+=2){
   303  			// 		b = c;
   304  			// 		b++;
   305  			//		if (!(a < 5))
   306  			// 			break;
   307  			// 		body
   308  			// }
   309  			tempSlice := c.Children()[0 : len(c.Children())-1]
   310  
   311  			var condition ast.IfStmt
   312  			condition.AddChild(nil)
   313  			var par ast.ParenExpr
   314  			par.Type = "bool"
   315  			par.AddChild(c.Children()[len(c.Children())-1])
   316  			var unitary ast.UnaryOperator
   317  			unitary.Type = "bool"
   318  			unitary.AddChild(&par)
   319  			unitary.Operator = "!"
   320  			condition.AddChild(&unitary)
   321  			var c ast.CompoundStmt
   322  			c.AddChild(&ast.BreakStmt{})
   323  			condition.AddChild(&c)
   324  			condition.AddChild(nil)
   325  
   326  			tempSlice = append(tempSlice, &condition)
   327  
   328  			var compound *ast.CompoundStmt
   329  			if children[4] != nil {
   330  				// if body is exist
   331  				compound = children[4].(*ast.CompoundStmt)
   332  			} else {
   333  				// if body is not exist
   334  				compound = new(ast.CompoundStmt)
   335  			}
   336  			compound.ChildNodes = append(tempSlice, compound.Children()...)
   337  			children[4] = compound
   338  			children[2] = nil
   339  		}
   340  	}
   341  
   342  	// The condition can be nil. This means an infinite loop and will be
   343  	// rendered in Go as "for {".
   344  	var condition goast.Expr
   345  	if children[2] != nil {
   346  		var conditionType string
   347  		var newPre, newPost []goast.Stmt
   348  
   349  		// The last parameter must be false because we are transpiling an
   350  		// expression - assignment operators need to be wrapped in closures.
   351  		condition, conditionType, newPre, newPost, err = atomicOperation(children[2], p)
   352  		if err != nil {
   353  			return nil, nil, nil, err
   354  		}
   355  		// null in C is false
   356  		if conditionType == types.NullPointer {
   357  			condition = util.NewIdent("false")
   358  			conditionType = "bool"
   359  		}
   360  
   361  		preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   362  
   363  		condition, err = types.CastExpr(p, condition, conditionType, "bool")
   364  		p.AddMessage(p.GenerateWarningMessage(err, n))
   365  
   366  		if condition == nil {
   367  			condition = util.NewNil()
   368  		}
   369  	}
   370  
   371  	if children[4] == nil {
   372  		// for case if operator FOR haven't body
   373  		children[4] = &ast.CompoundStmt{}
   374  	}
   375  	body, newPre, newPost, err := transpileToBlockStmt(children[4], p)
   376  	if err != nil {
   377  		err = fmt.Errorf("cannot transpile body. %v", err)
   378  		return nil, nil, nil, err
   379  	}
   380  	if body == nil {
   381  		return nil, nil, nil, fmt.Errorf("body of For cannot be nil")
   382  	}
   383  
   384  	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
   385  
   386  	// avoid extra block around FOR
   387  	if len(preStmts) == 0 && len(postStmts) == 0 {
   388  		return &goast.ForStmt{
   389  			Init: init,
   390  			Cond: condition,
   391  			Post: post,
   392  			Body: body,
   393  		}, preStmts, postStmts, nil
   394  	}
   395  
   396  	// for avoid duplication of init values for
   397  	// case with 2 for`s
   398  	var block goast.BlockStmt
   399  	var forStmt = goast.ForStmt{
   400  		Init: init,
   401  		Cond: condition,
   402  		Post: post,
   403  		Body: body,
   404  	}
   405  	block.List = combineStmts(preStmts, &forStmt, postStmts)
   406  	block.Lbrace = 1
   407  
   408  	return &block, nil, nil, nil
   409  }
   410  
   411  // transpileWhileStmt - transpiler for operator While.
   412  // We have only operator FOR in Go, but in C we also have
   413  // operator WHILE. So, we have to convert to operator FOR.
   414  // We choose directly conversion  from AST C code to AST C code, for
   415  // - avoid duplicate of code in realization WHILE and FOR.
   416  // - create only one operator FOR powerful.
   417  // Example of C code with operator WHILE:
   418  //
   419  //	while(i > 0){
   420  //		printf("While: %d\n",i);
   421  //		i--;
   422  //	}
   423  //
   424  // AST for that code:
   425  //
   426  //	|-WhileStmt 0x2530a10 <line:6:2, line:9:2>
   427  //	| |-<<<NULL>>>
   428  //	| |-BinaryOperator 0x25307f0 <line:6:8, col:12> 'int' '>'
   429  //	| | |-ImplicitCastExpr 0x25307d8 <col:8> 'int' <LValueToRValue>
   430  //	| | | `-DeclRefExpr 0x2530790 <col:8> 'int' lvalue Var 0x25306f8 'i' 'int'
   431  //	| | `-IntegerLiteral 0x25307b8 <col:12> 'int' 0
   432  //	| `-CompoundStmt 0x25309e8 <col:14, line:9:2>
   433  //	|   |-CallExpr 0x2530920 <line:7:3, col:25> 'int'
   434  //	|   | |-ImplicitCastExpr 0x2530908 <col:3> 'int (*)(const char *, ...)' <FunctionToPointerDecay>
   435  //	|   | | `-DeclRefExpr 0x2530818 <col:3> 'int (const char *, ...)' Function 0x2523ee8 'printf' 'int (const char *, ...)'
   436  //	|   | |-ImplicitCastExpr 0x2530970 <col:10> 'const char *' <BitCast>
   437  //	|   | | `-ImplicitCastExpr 0x2530958 <col:10> 'char *' <ArrayToPointerDecay>
   438  //	|   | |   `-StringLiteral 0x2530878 <col:10> 'char [11]' lvalue "While: %d\n"
   439  //	|   | `-ImplicitCastExpr 0x2530988 <col:24> 'int' <LValueToRValue>
   440  //	|   |   `-DeclRefExpr 0x25308b0 <col:24> 'int' lvalue Var 0x25306f8 'i' 'int'
   441  //	|   `-UnaryOperator 0x25309c8 <line:8:3, col:4> 'int' postfix '--'
   442  //	|     `-DeclRefExpr 0x25309a0 <col:3> 'int' lvalue Var 0x25306f8 'i' 'int'
   443  //
   444  // Example of C code with operator FOR:
   445  //
   446  //	for (;i > 0;){
   447  //		printf("For: %d\n",i);
   448  //		i--;
   449  //	}
   450  //
   451  // AST for that code:
   452  //
   453  //	|-ForStmt 0x2530d08 <line:11:2, line:14:2>
   454  //	| |-<<<NULL>>>
   455  //	| |-<<<NULL>>>
   456  //	| |-BinaryOperator 0x2530b00 <line:11:8, col:12> 'int' '>'
   457  //	| | |-ImplicitCastExpr 0x2530ae8 <col:8> 'int' <LValueToRValue>
   458  //	| | | `-DeclRefExpr 0x2530aa0 <col:8> 'int' lvalue Var 0x25306f8 'i' 'int'
   459  //	| | `-IntegerLiteral 0x2530ac8 <col:12> 'int' 0
   460  //	| |-<<<NULL>>>
   461  //	| `-CompoundStmt 0x2530ce0 <col:15, line:14:2>
   462  //	|   |-CallExpr 0x2530bf8 <line:12:3, col:23> 'int'
   463  //	|   | |-ImplicitCastExpr 0x2530be0 <col:3> 'int (*)(const char *, ...)' <FunctionToPointerDecay>
   464  //	|   | | `-DeclRefExpr 0x2530b28 <col:3> 'int (const char *, ...)' Function 0x2523ee8 'printf' 'int (const char *, ...)'
   465  //	|   | |-ImplicitCastExpr 0x2530c48 <col:10> 'const char *' <BitCast>
   466  //	|   | | `-ImplicitCastExpr 0x2530c30 <col:10> 'char *' <ArrayToPointerDecay>
   467  //	|   | |   `-StringLiteral 0x2530b88 <col:10> 'char [9]' lvalue "For: %d\n"
   468  //	|   | `-ImplicitCastExpr 0x2530c60 <col:22> 'int' <LValueToRValue>
   469  //	|   |   `-DeclRefExpr 0x2530bb8 <col:22> 'int' lvalue Var 0x25306f8 'i' 'int'
   470  //	|   `-UnaryOperator 0x2530ca0 <line:13:3, col:4> 'int' postfix '--'
   471  //	|     `-DeclRefExpr 0x2530c78 <col:3> 'int' lvalue Var 0x25306f8 'i' 'int'
   472  func transpileWhileStmt(n *ast.WhileStmt, p *program.Program) (
   473  	goast.Stmt, []goast.Stmt, []goast.Stmt, error) {
   474  
   475  	for i := 0; i < len(n.Children()); i++ {
   476  		if n.ChildNodes[0] == nil {
   477  			n.ChildNodes = n.ChildNodes[1:]
   478  		}
   479  		break
   480  	}
   481  
   482  	var forOperator ast.ForStmt
   483  	forOperator.AddChild(nil)
   484  	forOperator.AddChild(nil)
   485  	forOperator.AddChild(n.Children()[0])
   486  	forOperator.AddChild(nil)
   487  	if len(n.Children()) > 1 {
   488  		if n.Children()[1] == nil {
   489  			// added for case if WHILE haven't body, for example:
   490  			// while(0);
   491  			n.Children()[1] = &ast.CompoundStmt{}
   492  		}
   493  		forOperator.AddChild(n.Children()[1])
   494  	} else {
   495  		forOperator.AddChild(&ast.CompoundStmt{})
   496  	}
   497  
   498  	return transpileForStmt(&forOperator, p)
   499  }
   500  
   501  // transpileDoStmt - transpiler for operator Do...While
   502  // We have only operators FOR and IF in Go, but in C we also have
   503  // operator DO...WHILE. So, we have to convert to operators FOR and IF.
   504  // We choose directly conversion  from AST C code to AST C code, for:
   505  // - avoid duplicate of code in realization DO...WHILE and FOR.
   506  // - create only one powerful operator FOR.
   507  // Example of C code with operator DO...WHILE:
   508  //
   509  //	do{
   510  //		printf("While: %d\n",i);
   511  //		i--;
   512  //	}while(i > 0);
   513  //
   514  // AST for that code:
   515  //
   516  //	|-DoStmt 0x3bb1a68 <line:7:2, line:10:14>
   517  //	| |-CompoundStmt 0x3bb19b8 <line:7:4, line:10:2>
   518  //	| | |-CallExpr 0x3bb18f0 <line:8:3, col:25> 'int'
   519  //	| | | |-ImplicitCastExpr 0x3bb18d8 <col:3> 'int (*)(const char *, ...)' <FunctionToPointerDecay>
   520  //	| | | | `-DeclRefExpr 0x3bb17e0 <col:3> 'int (const char *, ...)' Function 0x3ba4ee8 'printf' 'int (const char *, ...)'
   521  //	| | | |-ImplicitCastExpr 0x3bb1940 <col:10> 'const char *' <BitCast>
   522  //	| | | | `-ImplicitCastExpr 0x3bb1928 <col:10> 'char *' <ArrayToPointerDecay>
   523  //	| | | |   `-StringLiteral 0x3bb1848 <col:10> 'char [11]' lvalue "While: %d\n"
   524  //	| | | `-ImplicitCastExpr 0x3bb1958 <col:24> 'int' <LValueToRValue>
   525  //	| | |   `-DeclRefExpr 0x3bb1880 <col:24> 'int' lvalue Var 0x3bb16f8 'i' 'int'
   526  //	| | `-UnaryOperator 0x3bb1998 <line:9:3, col:4> 'int' postfix '--'
   527  //	| |   `-DeclRefExpr 0x3bb1970 <col:3> 'int' lvalue Var 0x3bb16f8 'i' 'int'
   528  //	| `-BinaryOperator 0x3bb1a40 <line:10:9, col:13> 'int' '>'
   529  //	|   |-ImplicitCastExpr 0x3bb1a28 <col:9> 'int' <LValueToRValue>
   530  //	|   | `-DeclRefExpr 0x3bb19e0 <col:9> 'int' lvalue Var 0x3bb16f8 'i' 'int'
   531  //	|   `-IntegerLiteral 0x3bb1a08 <col:13> 'int' 0
   532  //
   533  // Example of C code with operator FOR:
   534  //
   535  //	for(;;){
   536  //		printf("For: %d\n",i);
   537  //		i--;
   538  //		if(!(i>0)){
   539  //			break;
   540  //		}
   541  //	}
   542  //
   543  // AST for that code:
   544  //
   545  //	|-ForStmt 0x3bb1e08 <line:12:2, line:18:2>
   546  //	| |-<<<NULL>>>
   547  //	| |-<<<NULL>>>
   548  //	| |-<<<NULL>>>
   549  //	| |-<<<NULL>>>
   550  //	| `-CompoundStmt 0x3bb1dd8 <line:12:9, line:18:2>
   551  //	|   |-CallExpr 0x3bb1bc8 <line:13:3, col:23> 'int'
   552  //	|   | |-ImplicitCastExpr 0x3bb1bb0 <col:3> 'int (*)(const char *, ...)' <FunctionToPointerDecay>
   553  //	|   | | `-DeclRefExpr 0x3bb1af8 <col:3> 'int (const char *, ...)' Function 0x3ba4ee8 'printf' 'int (const char *, ...)'
   554  //	|   | |-ImplicitCastExpr 0x3bb1c18 <col:10> 'const char *' <BitCast>
   555  //	|   | | `-ImplicitCastExpr 0x3bb1c00 <col:10> 'char *' <ArrayToPointerDecay>
   556  //	|   | |   `-StringLiteral 0x3bb1b58 <col:10> 'char [9]' lvalue "For: %d\n"
   557  //	|   | `-ImplicitCastExpr 0x3bb1c30 <col:22> 'int' <LValueToRValue>
   558  //	|   |   `-DeclRefExpr 0x3bb1b88 <col:22> 'int' lvalue Var 0x3bb16f8 'i' 'int'
   559  //	|   |-UnaryOperator 0x3bb1c70 <line:14:3, col:4> 'int' postfix '--'
   560  //	|   | `-DeclRefExpr 0x3bb1c48 <col:3> 'int' lvalue Var 0x3bb16f8 'i' 'int'
   561  //	|   `-IfStmt 0x3bb1da8 <line:15:3, line:17:3>
   562  //	|     |-<<<NULL>>>
   563  //	|     |-UnaryOperator 0x3bb1d60 <line:15:6, col:11> 'int' prefix '!'
   564  //	|     | `-ParenExpr 0x3bb1d40 <col:7, col:11> 'int'
   565  //	|     |   `-BinaryOperator 0x3bb1d18 <col:8, col:10> 'int' '>'
   566  //	|     |     |-ImplicitCastExpr 0x3bb1d00 <col:8> 'int' <LValueToRValue>
   567  //	|     |     | `-DeclRefExpr 0x3bb1c90 <col:8> 'int' lvalue Var 0x3bb16f8 'i' 'int'
   568  //	|     |     `-IntegerLiteral 0x3bb1ce0 <col:10> 'int' 0
   569  //	|     |-CompoundStmt 0x3bb1d88 <col:13, line:17:3>
   570  //	|     | `-BreakStmt 0x3bb1d80 <line:16:4>
   571  //	|     `-<<<NULL>>>
   572  func transpileDoStmt(n *ast.DoStmt, p *program.Program) (
   573  	goast.Stmt, []goast.Stmt, []goast.Stmt, error) {
   574  	var forOperator ast.ForStmt
   575  	forOperator.AddChild(nil)
   576  	forOperator.AddChild(nil)
   577  	forOperator.AddChild(nil)
   578  	forOperator.AddChild(nil)
   579  	c := &ast.CompoundStmt{}
   580  	if n.Children()[0] != nil {
   581  		if comp, ok := n.Children()[0].(*ast.CompoundStmt); ok {
   582  			c = comp
   583  		} else {
   584  			c.AddChild(n.Children()[0])
   585  		}
   586  	}
   587  	if n.Children()[1] != nil {
   588  		ifBreak := createIfWithNotConditionAndBreak(n.Children()[1])
   589  		c.AddChild(&ifBreak)
   590  	}
   591  	forOperator.AddChild(c)
   592  	return transpileForStmt(&forOperator, p)
   593  }
   594  
   595  // createIfWithNotConditionAndBreak - create operator IF like on next example
   596  // of C code:
   597  //
   598  //	if ( !(condition) ) {
   599  //			break;
   600  //	}
   601  //
   602  // Example of AST tree:
   603  //
   604  //	`-IfStmt 0x3bb1da8 <line:15:3, line:17:3>
   605  //	  |-<<<NULL>>>
   606  //	  |-UnaryOperator 0x3bb1d60 <line:15:6, col:11> 'int' prefix '!'
   607  //	  | `-ParenExpr 0x3bb1d40 <col:7, col:11> 'int'
   608  //	  |   `- CONDITION
   609  //	  |-CompoundStmt 0x3bb1d88 <col:13, line:17:3>
   610  //	  | `-BreakStmt 0x3bb1d80 <line:16:4>
   611  //	  `-<<<NULL>>>
   612  func createIfWithNotConditionAndBreak(condition ast.Node) (ifStmt ast.IfStmt) {
   613  	ifStmt.AddChild(nil)
   614  
   615  	var par ast.ParenExpr
   616  	var unitary ast.UnaryOperator
   617  
   618  	if typ, ok := ast.GetTypeIfExist(condition); ok {
   619  		par.Type = *typ
   620  		unitary.Type = *typ
   621  	} else {
   622  		panic(fmt.Errorf("type %T is not implemented in createIfWithNotConditionAndBreak", condition))
   623  	}
   624  
   625  	par.AddChild(condition)
   626  	unitary.Operator = "!"
   627  	unitary.AddChild(&par)
   628  
   629  	ifStmt.AddChild(&unitary)
   630  
   631  	var c ast.CompoundStmt
   632  	c.AddChild(&ast.BreakStmt{})
   633  	ifStmt.AddChild(&c)
   634  	ifStmt.AddChild(nil)
   635  
   636  	return
   637  }
   638  
   639  func transpileContinueStmt(n *ast.ContinueStmt, p *program.Program) (*goast.BranchStmt, error) {
   640  	return &goast.BranchStmt{
   641  		Tok: token.CONTINUE,
   642  	}, nil
   643  }