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

     1  package transpiler
     2  
     3  import (
     4  	"fmt"
     5  	goast "go/ast"
     6  	"go/token"
     7  	"strings"
     8  
     9  	"github.com/Konstantin8105/c4go/ast"
    10  	"github.com/Konstantin8105/c4go/program"
    11  	"github.com/Konstantin8105/c4go/types"
    12  	"github.com/Konstantin8105/c4go/util"
    13  )
    14  
    15  func transpileVAArgExpr(n *ast.VAArgExpr, p *program.Program) (
    16  	expr goast.Expr,
    17  	exprType string,
    18  	preStmts []goast.Stmt,
    19  	postStmts []goast.Stmt,
    20  	err error) {
    21  	defer func() {
    22  		if err != nil {
    23  			err = fmt.Errorf("cannot transpileVAArgExpr. %v", err)
    24  		}
    25  	}()
    26  	// -VAArgExpr 'int'
    27  	//  `-ImplicitCastExpr 'struct __va_list_tag *' <ArrayToPointerDecay>
    28  	//    `-DeclRefExpr 'va_list':'...' lvalue Var 'ap' 'va_list':'...'
    29  
    30  	p.IsHaveVaList = true
    31  
    32  	expr, exprType, preStmts, postStmts, err = atomicOperation(n.Children()[0], p)
    33  	if err != nil {
    34  		return expr, exprType, preStmts, postStmts, err
    35  	}
    36  
    37  	goType, err := types.ResolveType(p, n.Type)
    38  	if err != nil {
    39  		return expr, exprType, preStmts, postStmts, err
    40  	}
    41  
    42  	expr = &goast.TypeAssertExpr{
    43  		X:      util.NewCallExpr(va_arg, expr),
    44  		Lparen: 1,
    45  		Type:   goast.NewIdent(goType),
    46  	}
    47  	exprType = n.Type
    48  	return
    49  }
    50  
    51  func getVaListStruct() string {
    52  	return `
    53  
    54  // va_list is C4GO implementation of va_list from "stdarg.h"
    55  type va_list struct{
    56  	position int
    57  	Slice    []interface{}
    58  }
    59  
    60  func create_va_list(list []interface{}) * va_list{
    61  	return &va_list{
    62  		position: 0,
    63  		Slice   : list,
    64  	}
    65  }
    66  
    67  func va_start(v * va_list, count interface{}) {
    68  	v.position = 0
    69  }
    70  
    71  func va_end(v * va_list) {
    72  	// do nothing
    73  }
    74  
    75  func va_arg(v * va_list) interface{} {
    76  	defer func(){
    77  		 v.position++	
    78  	}()
    79  	value := v.Slice[v.position]
    80  	switch value.(type) {
    81  		case int: 
    82  			return int32(value.(int))
    83  		default:
    84  			return value
    85  	}
    86  }
    87  
    88  `
    89  }
    90  
    91  const (
    92  	create_va_list string = "create_va_list"
    93  	va_arg                = "va_arg"
    94  	va_start              = "va_start"
    95  	va_end                = "va_end"
    96  )
    97  
    98  func VaListInit(p *program.Program, name string) []goast.Decl {
    99  	// variable for va_list. see "variadic function"
   100  	// header : <stdarg.h>
   101  	// Example :
   102  	// DeclStmt 0x2fd87e0 <line:442:2, col:14>
   103  	// `-VarDecl 0x2fd8780 <col:2, col:10> col:10 used args 'va_list':'struct __va_list_tag [1]'
   104  	// Result:
   105  	// ... - convert to - c4goArgs ...interface{}
   106  	// var args = c4goArgs
   107  
   108  	p.IsHaveVaList = true
   109  
   110  	return []goast.Decl{&goast.GenDecl{
   111  		Tok: token.VAR,
   112  		Specs: []goast.Spec{
   113  			&goast.ValueSpec{
   114  				Names: []*goast.Ident{util.NewIdent(name)},
   115  				Values: []goast.Expr{
   116  					util.NewCallExpr(create_va_list, util.NewIdent("c4goArgs")),
   117  				},
   118  			},
   119  		},
   120  	}}
   121  }
   122  
   123  func changeVaListFuncs(functionName *string) {
   124  	switch *functionName {
   125  	case "__builtin_va_start":
   126  		mod := va_start
   127  		*functionName = mod
   128  	case "__builtin_va_end":
   129  		mod := va_end
   130  		*functionName = mod
   131  	}
   132  	return
   133  }
   134  
   135  func ignoreVaListTypedef(name string) bool {
   136  	if strings.Contains(name, "va_list") {
   137  		return true
   138  	}
   139  	return false
   140  }