github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/transpiler/variables.go (about) 1 package transpiler 2 3 import ( 4 "fmt" 5 goast "go/ast" 6 "go/token" 7 "strconv" 8 "strings" 9 10 "github.com/Konstantin8105/c4go/ast" 11 "github.com/Konstantin8105/c4go/program" 12 "github.com/Konstantin8105/c4go/types" 13 "github.com/Konstantin8105/c4go/util" 14 ) 15 16 func transpileDeclRefExpr(n *ast.DeclRefExpr, p *program.Program) ( 17 expr *goast.Ident, exprType string, err error) { 18 19 if n.For == "EnumConstant" { 20 // clang don`t show enum constant with enum type, 21 // so we have to use hack for repair the type 22 if v, ok := p.EnumConstantToEnum[n.Name]; ok { 23 expr, exprType, err = util.NewIdent(n.Name), v, nil 24 return 25 } 26 } 27 28 if name, ok := program.DefinitionVariable[n.Name]; ok { 29 name = p.ImportType(name) 30 return util.NewIdent(name), n.Type, nil 31 } 32 33 if n.For == "Function" { 34 var includeFile string 35 includeFile, err = p.GetIncludeFileNameByFunctionSignature(n.Name, n.Type) 36 p.AddMessage(p.GenerateWarningMessage(err, n)) 37 if includeFile != "" && p.IncludeHeaderIsExists(includeFile) { 38 name := p.GetFunctionDefinition(n.Name).Substitution 39 if strings.Contains(name, ".") && !strings.Contains(name, "github") { 40 p.AddImport(strings.Split(name, ".")[0]) 41 } 42 return goast.NewIdent(name), n.Type, nil 43 } 44 } 45 46 theType := n.Type 47 expr = util.NewIdent(n.Name) 48 49 return expr, theType, nil 50 } 51 52 func getDefaultValueForVar(p *program.Program, a *ast.VarDecl) ( 53 expr []goast.Expr, _ string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 54 defer func() { 55 if err != nil { 56 err = fmt.Errorf("cannot getDefaultValueForVar : err = %v", err) 57 } 58 }() 59 if len(a.Children()) == 0 { 60 return nil, "", nil, nil, nil 61 } 62 63 defaultValue, defaultValueType, newPre, newPost, err := atomicOperation(a.Children()[0], p) 64 if err != nil { 65 return nil, defaultValueType, newPre, newPost, err 66 } 67 68 var values []goast.Expr 69 if !types.IsNullExpr(defaultValue) { 70 t, err := types.CastExpr(p, defaultValue, defaultValueType, a.Type) 71 if !p.AddMessage(p.GenerateWarningMessage(err, a)) { 72 values = append(values, t) 73 defaultValueType = a.Type 74 } 75 } 76 77 return values, defaultValueType, newPre, newPost, nil 78 } 79 80 // GenerateFuncType in according to types 81 // Type: *ast.FuncType { 82 // . Func: 13:7 83 // . Params: *ast.FieldList { 84 // . . Opening: 13:12 85 // . . List: []*ast.Field (len = 2) { 86 // . . . 0: *ast.Field { 87 // . . . . Type: *ast.Ident { 88 // . . . . . NamePos: 13:13 89 // . . . . . Name: "int" 90 // . . . . } 91 // . . . } 92 // . . . 1: *ast.Field { 93 // . . . . Type: *ast.Ident { 94 // . . . . . NamePos: 13:17 95 // . . . . . Name: "int" 96 // . . . . } 97 // . . . } 98 // . . } 99 // . } 100 // . Results: *ast.FieldList { 101 // . . Opening: - 102 // . . List: []*ast.Field (len = 1) { 103 // . . . 0: *ast.Field { 104 // . . . . Type: *ast.Ident { 105 // . . . . . NamePos: 13:21 106 // . . . . . Name: "string" 107 // . . . . } 108 // . . . } 109 // . . } 110 // . } 111 // } 112 func GenerateFuncType(fields, returns []string) *goast.FuncType { 113 var ft goast.FuncType 114 { 115 var fieldList goast.FieldList 116 fieldList.Opening = 1 117 fieldList.Closing = 2 118 for i := range fields { 119 fieldList.List = append(fieldList.List, &goast.Field{Type: &goast.Ident{Name: fields[i]}}) 120 } 121 ft.Params = &fieldList 122 } 123 { 124 var fieldList goast.FieldList 125 for i := range returns { 126 fieldList.List = append(fieldList.List, &goast.Field{Type: &goast.Ident{Name: returns[i]}}) 127 } 128 ft.Results = &fieldList 129 } 130 return &ft 131 } 132 133 // transpileInitListExpr. 134 // 135 // Examples: 136 // 137 // -InitListExpr 0x3cea0f0 <col:29, line:54:1> 'char *[256]' 138 // 139 // |-array filler 140 // | `-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *' 141 // |-ImplicitCastExpr 0x3cea138 <line:51:10> 'char *' <ArrayToPointerDecay> 142 // | `-StringLiteral 0x3ce9f00 <col:10> 'char [3]' lvalue "fa" 143 // |-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *' 144 // |-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *' 145 func transpileInitListExpr(e *ast.InitListExpr, p *program.Program) ( 146 expr goast.Expr, exprType string, err error) { 147 defer func() { 148 if err != nil { 149 err = fmt.Errorf("cannot transpileInitListExpr. err = %v", err) 150 } 151 }() 152 resp := []goast.Expr{} 153 e.Type1 = util.GenerateCorrectType(e.Type1) 154 e.Type2 = util.GenerateCorrectType(e.Type2) 155 exprType = e.Type1 156 157 for _, node := range e.Children() { 158 // Skip ArrayFiller 159 if _, ok := node.(*ast.ArrayFiller); ok { 160 continue 161 } 162 163 // var expr goast.Expr 164 // var eType string 165 // var err error 166 167 expr, _, _, _, err := transpileToExpr(node, p, true) 168 p.AddMessage(p.GenerateWarningMessage(err, node)) 169 170 resp = append(resp, expr) 171 } 172 173 goType, err := types.ResolveType(p, e.Type1) 174 if err != nil { 175 return nil, "", err 176 } 177 178 arrayType, arraySize := types.GetArrayTypeAndSize(e.Type1) 179 if arraySize > 0 { 180 for i := len(resp); i < arraySize; i++ { 181 zero, _ := zeroValue(p, arrayType) 182 resp = append(resp, zero) 183 } 184 exprType = arrayType + "[]" 185 } 186 187 structType, isStruct := p.Structs[e.Type1] 188 if !isStruct { 189 if tt, ok := p.GetBaseTypeOfTypedef(e.Type1); ok { 190 structType, isStruct = p.Structs[tt] 191 } 192 } 193 if isStruct { 194 for fieldPos, node := range resp { 195 if fieldType, ok := structType.Fields[structType.FieldNames[fieldPos]]; ok { 196 if ft, ok := fieldType.(string); ok { 197 198 arr, arrFieldSize := types.GetArrayTypeAndSize(ft) 199 if arrFieldSize > 0 { 200 201 var fixed bool 202 switch v := node.(type) { 203 case *goast.CompositeLit: 204 if id, ok := v.Type.(*goast.Ident); ok { 205 goType, err := types.ResolveType(p, arr) 206 p.AddMessage(p.GenerateWarningMessage(err, nil)) 207 id.Name = fmt.Sprintf("[%d]%s", arrFieldSize, goType) 208 fixed = true 209 } 210 case *goast.CallExpr: 211 // From: 212 // 0 *ast.CallExpr { 213 // 1 . Fun: *ast.Ident { 214 // 3 . . Name: "[]byte" 215 // 4 . } 216 // 6 . Args: []ast.Expr (len = 1) { 217 // 7 . . 0: *ast.BasicLit { 218 // 9 . . . Kind: STRING 219 // 10 . . . Value: "\"dream\\x00\"" 220 // 11 . . } 221 // 12 . } 222 // 15 } 223 if id, ok := v.Fun.(*goast.Ident); ok && id.Name == "[]byte" { 224 if len(v.Args) == 1 { 225 if bl, ok := v.Args[0].(*goast.BasicLit); ok && bl.Kind == token.STRING { 226 var sl ast.StringLiteral 227 sl.Type = ft 228 sl.Value, err = strconv.Unquote(bl.Value) 229 p.AddMessage(p.GenerateWarningMessage(err, e)) 230 var ex goast.Expr 231 ex, _, err = transpileStringLiteral(p, &sl, true) 232 p.AddMessage(p.GenerateWarningMessage(err, e)) 233 resp[fieldPos] = ex 234 fixed = true 235 } 236 } 237 } 238 } 239 if !fixed { 240 err = fmt.Errorf("cannot fix slice to array for type : %T", expr) 241 } 242 } 243 } 244 } 245 } 246 } 247 248 if len(resp) == 1 && goType == "[]byte" { 249 return resp[0], exprType, nil 250 } 251 252 return &goast.CompositeLit{ 253 Lbrace: 1, 254 Type: goast.NewIdent(goType), 255 Elts: resp, 256 }, exprType, nil 257 } 258 259 func zeroValue(p *program.Program, cType string) (zero goast.Expr, zeroType string) { 260 zeroType = cType 261 goType, err := types.ResolveType(p, cType) 262 p.AddMessage(p.GenerateWarningMessage(err, nil)) 263 264 // for structs 265 if tt, ok := p.GetBaseTypeOfTypedef(cType); ok { 266 if _, ok := p.Structs[tt]; ok { 267 zero = goast.NewIdent(fmt.Sprintf("%s{}", goType)) 268 return 269 } 270 } 271 if _, ok := p.Structs[cType]; ok { 272 zero = goast.NewIdent(fmt.Sprintf("%s{}", goType)) 273 return 274 } 275 276 switch { 277 case goType == "byte": 278 zero = goast.NewIdent("'\\x00'") 279 case types.IsCPointer(cType, p): 280 zero = goast.NewIdent("nil") 281 case types.IsCArray(cType, p): 282 goType, err := types.ResolveType(p, cType) 283 p.AddMessage(p.GenerateWarningMessage(err, nil)) 284 zero = &goast.CompositeLit{ 285 Lbrace: 1, 286 Type: goast.NewIdent(goType), 287 } 288 default: 289 zero = goast.NewIdent("0") 290 } 291 292 return 293 } 294 295 func transpileDeclStmt(n *ast.DeclStmt, p *program.Program) ( 296 stmts []goast.Stmt, err error) { 297 298 if len(n.Children()) == 0 { 299 return 300 } 301 var tud ast.TranslationUnitDecl 302 tud.ChildNodes = n.Children() 303 var decls []goast.Decl 304 decls, err = transpileToNode(&tud, p) 305 if err != nil { 306 p.AddMessage(p.GenerateWarningMessage(err, n)) 307 err = nil 308 } 309 stmts = convertDeclToStmt(decls) 310 311 return 312 } 313 314 func transpileArraySubscriptExpr(n *ast.ArraySubscriptExpr, p *program.Program) ( 315 _ *goast.IndexExpr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 316 defer func() { 317 if err != nil { 318 err = fmt.Errorf("cannot transpile ArraySubscriptExpr. err = %v", err) 319 p.AddMessage(p.GenerateWarningMessage(err, n)) 320 } 321 }() 322 323 children := n.Children() 324 325 if un, ok := children[1].(*ast.UnaryOperator); ok && un.Operator == "-" && un.IsPrefix { 326 // from: 327 // ArraySubscriptExpr 'double' lvalue 328 // |-ImplicitCastExpr 'double *' <LValueToRValue> 329 // | `-DeclRefExpr 'double *' lvalue Var 0x2d19e58 'p' 'double *' 330 // `-UnaryOperator 'int' prefix '-' 331 // `-IntegerLiteral 'int' 1 332 // to: 333 // BinaryOperator 'double *' '-' 334 // |-ImplicitCastExpr 'double *' <LValueToRValue> 335 // | `-DeclRefExpr 'double *' lvalue Var 0x2d19e58 'p' 'double *' 336 // `-IntegerLiteral 'int' 1 337 338 t, ok := ast.GetTypeIfExist(children[0]) 339 if ok { 340 bin := &ast.BinaryOperator{ 341 Type: *t, 342 Operator: "-", 343 } 344 bin.AddChild(n.Children()[0]) 345 bin.AddChild(un.Children()[0]) 346 347 expression, _, newPre, newPost, err := atomicOperation(bin, p) 348 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 349 350 return &goast.IndexExpr{ 351 X: expression, 352 Index: goast.NewIdent("0"), 353 }, n.Type, preStmts, postStmts, err 354 } 355 } 356 357 expression, _, newPre, newPost, err := transpileToExpr(children[0], p, false) 358 if err != nil { 359 return nil, "", nil, nil, err 360 } 361 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 362 363 index, _, newPre, newPost, err := atomicOperation(children[1], p) 364 if err != nil { 365 return nil, "", nil, nil, err 366 } 367 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 368 369 // index, err = types.CastExpr(p, index, indexType, "int") 370 // if err != nil { 371 // return nil, "", nil, nil, err 372 // } 373 // index = util.NewCallExpr("int", index) 374 375 return &goast.IndexExpr{ 376 X: expression, 377 Index: index, 378 }, n.Type, preStmts, postStmts, nil 379 } 380 381 func transpileMemberExpr(n *ast.MemberExpr, p *program.Program) ( 382 _ goast.Expr, _ string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 383 defer func() { 384 if err != nil { 385 err = fmt.Errorf("cannot transpile MemberExpr. err = %v", err) 386 p.AddMessage(p.GenerateWarningMessage(err, n)) 387 } 388 }() 389 390 n.Type = util.GenerateCorrectType(n.Type) 391 n.Type2 = util.GenerateCorrectType(n.Type2) 392 393 originTypes := []string{n.Type, n.Type2} 394 if n.Children()[0] != nil { 395 switch v := n.Children()[0].(type) { 396 case *ast.ParenExpr: 397 originTypes = append(originTypes, v.Type) 398 originTypes = append(originTypes, v.Type2) 399 } 400 } 401 402 lhs, lType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false) 403 if err != nil { 404 return nil, "", nil, nil, err 405 } 406 407 baseType := lType 408 lType = util.GenerateCorrectType(lType) 409 410 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 411 412 // typedef 413 414 lhsTypes := [2]string{lType, lType} 415 416 if t, ok := ast.GetTypeIfExist(n.Children()[0]); ok { 417 lhsTypes[1] = *t 418 } 419 420 var structType *program.Struct 421 var lhsType string = lhsTypes[0] 422 for _, lhsTypeLocal := range lhsTypes { 423 // lhsType will be something like "struct foo" 424 structType = p.GetStruct(lhsTypeLocal) 425 // added for support "struct typedef" 426 if structType == nil { 427 structType = p.GetStruct("struct " + lhsTypeLocal) 428 } 429 // added for support "union typedef" 430 if structType == nil { 431 structType = p.GetStruct("union " + lhsTypeLocal) 432 } 433 // for anonymous structs 434 if structType == nil { 435 structType = p.GetStruct(baseType) 436 } 437 // for anonymous structs 438 if structType == nil { 439 structType = p.GetStruct(util.CleanCType(baseType)) 440 } 441 // typedef types 442 if structType == nil { 443 structType = p.GetStruct(p.TypedefType[baseType]) 444 } 445 if structType == nil { 446 t := types.GetBaseType(baseType) 447 structType = p.GetStruct(p.TypedefType[t]) 448 } 449 // other case 450 for _, t := range originTypes { 451 if structType == nil { 452 structType = p.GetStruct(util.CleanCType(t)) 453 } else { 454 break 455 } 456 if structType == nil { 457 structType = p.GetStruct(types.GetBaseType(t)) 458 } else { 459 break 460 } 461 } 462 463 if structType != nil { 464 lhsType = lhsTypeLocal 465 break 466 } 467 } 468 469 if n.Name == "" { 470 n.Name = generateNameFieldDecl(util.GenerateCorrectType(n.Type)) 471 } 472 rhs := n.Name 473 rhsType := "void *" 474 if structType == nil { 475 // This case should not happen in the future. Any structs should be 476 // either parsed correctly from the source or be manually setup when the 477 // parser starts if the struct if hidden or shared between libraries. 478 // 479 // Some other things to keep in mind: 480 // 1. Types need to be stripped of their pointer, 'FILE *' -> 'FILE'. 481 // 2. Types may refer to one or more other types in a chain that have 482 // to be resolved before the real field type can be determined. 483 err = fmt.Errorf("cannot determine type for LHS '%v'"+ 484 ", will use 'void *' for all fields. Is lvalue = %v. n.Name = %v. "+ 485 "Position = %v", 486 lhsTypes, n.IsLvalue, n.Name, n.Pos) 487 p.AddMessage(p.GenerateWarningMessage(err, n)) 488 err = nil // ignore error 489 } else { 490 if s, ok := structType.Fields[rhs].(string); ok { 491 rhsType = s 492 } else { 493 err = fmt.Errorf("cannot determine type for RHS '%v' of '%s', will use"+ 494 " 'void *' for all fields. Is lvalue = %v. n.Name = `%v`", 495 rhs, structType.Name, n.IsLvalue, n.Name) 496 p.AddMessage(p.GenerateWarningMessage(err, n)) 497 err = nil // ignore error 498 } 499 } 500 501 x := lhs 502 if n.IsPointer { 503 x = &goast.IndexExpr{X: x, Index: util.NewIntLit(0)} 504 } 505 506 // Check for member name translation. 507 lhsType = strings.TrimSpace(lhsType) 508 if lhsType[len(lhsType)-1] == '*' { 509 lhsType = lhsType[:len(lhsType)-len(" *")] 510 } 511 if str := p.GetStruct("c4go_" + lhsType); str != nil { 512 if alias, ok := str.Fields[rhs]; ok { 513 // change type 514 if str, ok := p.Structs[lhsType]; ok { 515 if name, ok := str.Fields[rhs].(string); ok { 516 n.Type = name 517 } 518 } 519 // change field 520 rhs = alias.(string) 521 goto Selector 522 } 523 } 524 525 // anonymous struct member? 526 if rhs == "" { 527 rhs = "anon" 528 } 529 530 if isUnionMemberExpr(p, n) { 531 return &goast.ParenExpr{ 532 Lparen: 1, 533 X: &goast.StarExpr{ 534 Star: 1, 535 X: &goast.CallExpr{ 536 Fun: &goast.SelectorExpr{ 537 X: x, 538 Sel: util.NewIdent(rhs), 539 }, 540 Lparen: 1, 541 }, 542 }, 543 }, n.Type, preStmts, postStmts, nil 544 } 545 546 Selector: 547 _ = rhsType 548 549 return &goast.SelectorExpr{ 550 X: x, 551 Sel: util.NewIdent(rhs), 552 }, n.Type, preStmts, postStmts, nil 553 } 554 555 // transpileImplicitValueInitExpr. 556 // 557 // Examples: 558 // 559 // |-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *' 560 func transpileImplicitValueInitExpr(n *ast.ImplicitValueInitExpr, p *program.Program) ( 561 expr goast.Expr, exprType string, _ []goast.Stmt, _ []goast.Stmt, err error) { 562 563 defer func() { 564 if err != nil { 565 err = fmt.Errorf("cannot transpileImplicitValueInitExpr. err = %v", err) 566 } 567 }() 568 expr, exprType = zeroValue(p, n.Type1) 569 return 570 571 }