translate_process.odin (17393B)
1 #+private file 2 package bindgen2 3 4 import "core:strings" 5 import "core:slice" 6 import "core:log" 7 import "core:math/bits" 8 import "core:unicode" 9 import "core:unicode/utf8" 10 import "core:fmt" 11 import "core:os" 12 13 @(private="package") 14 Translate_Process_Result :: struct { 15 // Comment at top of file 16 top_comment: string, 17 top_code: string, 18 link_prefix: string, 19 20 extra_imports: []string, 21 } 22 23 @(private="package") 24 translate_process :: proc(tcr: Translate_Collect_Result, config: Config, types: Type_List, decls: Decl_List) -> Translate_Process_Result { 25 forward_declare_resolved: map[string]bool 26 27 to_remove: map[string]struct{} 28 29 for r in config.remove { 30 to_remove[r] = {} 31 } 32 33 for &d in decls { 34 if d.name in to_remove { 35 d.invalid = true 36 continue 37 } 38 39 if d.is_forward_declare { 40 if d.name in forward_declare_resolved { 41 d.invalid = true 42 continue 43 } 44 45 forward_declare_resolved[d.name] = false 46 } 47 } 48 49 for &d in decls { 50 // A bit of a hack due to aliases being disregarded later. Perhaps we can change that? 51 if _, is_alias := resolve_type_definition(types, d.def, Type_Alias); is_alias { 52 continue 53 } 54 55 if !d.is_forward_declare && d.name in forward_declare_resolved { 56 forward_declare_resolved[d.name] = true 57 } 58 } 59 60 // Replace types 61 for &d in decls { 62 override: bool 63 override_definition_text: string 64 65 if type_override, has_override := config.type_overrides[d.name]; has_override { 66 override = true 67 override_definition_text = type_override 68 } 69 70 // Don't override if this is type is an alias that has the same name as the aliased name. 71 // Doing that override will just make this alias not get ignored, as it is no longer just 72 // doing Some_Type :: Some_Type, but rather Some_New_Type :: Some_Type. 73 if alias, is_alias := resolve_type_definition(types, d.def, Type_Alias); is_alias { 74 named_alias, alias_is_named := alias.aliased_type.(Type_Name) 75 if alias_is_named && d.name == string(named_alias) { 76 override = false 77 } 78 } 79 80 if override { 81 d.def = Fixed_Value(override_definition_text) 82 } 83 } 84 85 remove_enum_members: map[string]struct{} 86 remove_enum_suffixes: [dynamic]string 87 remove_enum_prefixes: [dynamic]string 88 89 for e in config.remove_enum_members { 90 if strings.has_prefix(e, "*") { 91 append(&remove_enum_suffixes, e[1:]) 92 } else if strings.has_suffix(e, "*") { 93 append(&remove_enum_prefixes, e[:len(e) - 1]) 94 } else { 95 remove_enum_members[e] = {} 96 } 97 } 98 99 // Declared here to reuse. 100 bit_set_make_constant: map[string]int 101 102 for &d, i in decls { 103 if i == 0 { 104 d.invalid = true 105 continue 106 } 107 108 if d.is_forward_declare && forward_declare_resolved[d.name] { 109 d.invalid = true 110 continue 111 } 112 113 if d.name == "" { 114 d.invalid = true 115 log.errorf("Declaration has no name: %v", d.name) 116 continue 117 } 118 119 if d.def == nil { 120 d.invalid = true 121 log.errorf("Type used in declaration %v is zero", d.name) 122 continue 123 } 124 125 if _, is_fixed_value := d.def.(Fixed_Value); is_fixed_value { 126 continue 127 } 128 129 if _, is_type_name := d.def.(Type_Name); is_type_name { 130 continue 131 } 132 133 if _, is_macro_name := d.def.(Macro_Name); is_macro_name { 134 continue 135 } 136 137 type := &types[d.def.(Type_Index)] 138 139 #partial switch &v in type { 140 case Type_Enum: 141 { 142 new_members: [dynamic]Type_Enum_Member 143 144 member_loop: for m in v.members { 145 if m.name in remove_enum_members { 146 continue 147 } 148 149 for p in remove_enum_suffixes { 150 if strings.has_suffix(m.name, p) { 151 continue member_loop 152 } 153 } 154 155 for p in remove_enum_prefixes { 156 if strings.has_prefix(m.name, p) { 157 continue member_loop 158 } 159 } 160 161 append(&new_members, m) 162 } 163 164 v.members = new_members[:] 165 } 166 167 bit_set_enum_name, bit_setify := config.bit_setify[d.name] 168 169 if bit_setify { 170 clear(&bit_set_make_constant) 171 172 bs_idx := add_type(types, Type_Bit_Set { 173 enum_type = d.def.(Type_Index), 174 enum_decl_name = Type_Name(bit_set_enum_name), 175 }) 176 177 new_members: [dynamic]Type_Enum_Member 178 179 // log2-ify value so `2` becomes `1`, `4` becomes `2` etc. 180 for m in v.members { 181 if m.value == 0 { 182 continue 183 } 184 185 if bits.count_ones(m.value) != 1 { 186 // Not a power of two, so not part of a bit_set. Save it for later for making 187 // it into a constant. 188 bs_constant_idx := add_type(types, Type_Bit_Set_Constant { 189 bit_set_type = bs_idx, 190 bit_set_type_name = Type_Name(d.name), 191 value = m.value, 192 }) 193 194 all_constant := strings.to_screaming_snake_case(strings.trim_prefix(strings.to_lower(m.name), strings.to_lower(config.remove_type_prefix))) 195 196 add_decl(decls, { 197 original_line = d.original_line + 2, 198 name = all_constant, 199 def = bs_constant_idx, 200 explicitly_created = true, 201 }) 202 203 continue 204 } 205 206 append(&new_members, Type_Enum_Member { 207 name = m.name, 208 value = int(bits.log2(uint(m.value))), 209 comment_before = m.comment_before, 210 comment_on_right = m.comment_on_right, 211 }) 212 } 213 214 v.members = new_members[:] 215 216 enum_decl := d 217 enum_decl.comment_before = "" 218 enum_decl.side_comment = "" 219 d.def = bs_idx 220 d.original_line += 1 221 222 enum_decl.name = bit_set_enum_name 223 224 add_decl(decls, enum_decl) 225 } 226 227 case Type_Struct: 228 for &f in v.fields { 229 if len(f.names) != 1 { 230 continue 231 } 232 233 field_key := fmt.tprintf("%s.%s", d.name, f.names[0]) 234 if override, has_override := config.struct_field_overrides[field_key]; has_override { 235 if override == "[^]" { 236 if ptr_type, is_ptr_type := resolve_type_definition(types, f.type, Type_Pointer); is_ptr_type { 237 f.type = add_type(types, Type_Multipointer { 238 pointed_to_type = ptr_type.pointed_to_type, 239 }) 240 } 241 } else if override == "using" { 242 f.is_using = true 243 } else { 244 f.type = Fixed_Value(override) 245 } 246 } 247 248 if proc_type := resolve_type_definition_ptr(types, f.type, Type_Procedure); proc_type != nil { 249 for ¶m in proc_type.parameters { 250 key := fmt.tprintf("%s.%s.%s", d.name, f.names[0], param.name) 251 252 if default, has_default := config.procedure_parameter_defaults[key]; has_default { 253 param.default = default 254 } 255 256 if override, has_override := config.procedure_type_overrides[key]; has_override { 257 override_procedure_parameter(¶m, types, override) 258 } 259 } 260 } 261 262 if tag, has_tag := config.struct_field_tags[field_key]; has_tag { 263 f.tag = tag 264 } 265 } 266 case Type_Procedure: 267 for &p in v.parameters { 268 param_key := fmt.tprintf("%s.%s", d.name, p.name) 269 if override, has_override := config.procedure_type_overrides[param_key]; has_override { 270 override_procedure_parameter(&p, types, override) 271 } 272 273 if default, has_default := config.procedure_parameter_defaults[param_key]; has_default { 274 p.default = default 275 } 276 } 277 278 return_override_key := d.name 279 280 if override, has_override := config.procedure_type_overrides[return_override_key]; has_override { 281 if override == "[^]" { 282 if ptr_type, is_ptr_type := resolve_type_definition(types, v.result_type, Type_Pointer); is_ptr_type { 283 v.result_type = add_type(types, Type_Multipointer { 284 pointed_to_type = ptr_type.pointed_to_type, 285 }) 286 } 287 } else { 288 v.result_type = Fixed_Value(override) 289 } 290 } 291 } 292 } 293 294 top_code: string 295 296 if config.imports_file != "" { 297 if imports, imports_ok := os.read_entire_file(config.imports_file); imports_ok { 298 top_code = string(imports) 299 } 300 } else if config.import_lib != "" { 301 top_code = fmt.tprintf("foreign import lib \"%v\"\n_ :: lib", config.import_lib) 302 } 303 304 if config.procedures_at_end { 305 context.user_ptr = types 306 slice.sort_by(decls[:], proc(i, j: Decl) -> bool { 307 types := (Type_List)(context.user_ptr) 308 _, i_is_proc := resolve_type_definition(types, i.def, Type_Procedure) 309 _, j_is_proc := resolve_type_definition(types, j.def, Type_Procedure) 310 311 if i_is_proc != j_is_proc { 312 return j_is_proc 313 } 314 315 return i.original_line < j.original_line 316 }) 317 } else { 318 slice.sort_by(decls[:], proc(i, j: Decl) -> bool { 319 return i.original_line < j.original_line 320 }) 321 } 322 323 // Run this last! Otherwise mapping that assumes things has their original names may fail. 324 resolve_final_names(types, decls, config) 325 326 return { 327 top_comment = extract_top_comment(tcr.source), 328 top_code = top_code, 329 link_prefix = config.remove_function_prefix, 330 extra_imports = tcr.extra_imports, 331 } 332 } 333 334 strip_enum_member_prefixes :: proc(e: ^Type_Enum) { 335 overlap_length := 0 336 337 if len(e.members) > 1 { 338 overlap_length_source := e.members[0].name 339 overlap_length = len(overlap_length_source) 340 341 for idx in 1..<len(e.members) { 342 mn := e.members[idx].name 343 length := strings.prefix_length(mn, overlap_length_source) 344 345 if length < overlap_length { 346 overlap_length = length 347 overlap_length_source = mn 348 } 349 } 350 351 if overlap_length > 0 { 352 back_off := false 353 underscore_in_member := false 354 355 for &m in e.members { 356 if strings.contains(m.name[overlap_length:], "_") { 357 underscore_in_member = true 358 break 359 } 360 } 361 362 if !underscore_in_member && strings.count(overlap_length_source, "_") > 1 { 363 back_off = true 364 } 365 366 for &m in e.members { 367 if overlap_length == len(m.name) { 368 back_off = true 369 break 370 } 371 } 372 373 // We stripped too much! Back off to nearest underscore or camelCase change 374 if back_off { 375 found_underscore := false 376 #reverse for c, i in overlap_length_source { 377 if c == '_' { 378 overlap_length = i + 1 379 found_underscore = true 380 break 381 } 382 } 383 384 // No underscore found, try camelCase 385 if !found_underscore { 386 last_letter: rune 387 388 #reverse for c in overlap_length_source { 389 if unicode.is_letter(c) { 390 last_letter = c 391 break 392 } 393 } 394 395 #reverse for c, i in overlap_length_source { 396 if unicode.is_letter(c) && unicode.is_upper(c) != unicode.is_upper(last_letter) { 397 overlap_length = i + 1 398 break 399 } 400 } 401 } 402 } 403 } 404 } 405 406 for &m in e.members { 407 name_without_overlap := m.name[overlap_length:] 408 409 if len(name_without_overlap) != 0 { 410 m.name = name_without_overlap 411 412 if is_number(m.name[0]) { 413 m.name = fmt.tprintf("_%v", m.name) 414 } 415 } 416 } 417 } 418 419 // Give all types and declarations their final names. Based on config, but also strips enum prefixes etc. 420 resolve_final_names :: proc(types: Type_List, decls: Decl_List, config: Config) { 421 for &t in types { 422 switch &tv in t { 423 case Type_Unknown: 424 425 case Type_Pointer: 426 if type_name, is_type_name := tv.pointed_to_type.(Type_Name); is_type_name { 427 tv.pointed_to_type = final_type_name(type_name, config) 428 } 429 430 case Type_Multipointer: 431 if type_name, is_type_name := tv.pointed_to_type.(Type_Name); is_type_name { 432 tv.pointed_to_type = final_type_name(type_name, config) 433 } 434 435 case Type_Pointer_By_Ptr: 436 if type_name, is_type_name := tv.pointed_to_type.(Type_Name); is_type_name { 437 tv.pointed_to_type = final_type_name(type_name, config) 438 } 439 440 case Type_Raw_Pointer: 441 442 case Type_CString: 443 444 case Type_Struct: 445 for &f in tv.fields { 446 for &n in f.names { 447 n = ensure_name_valid(n) 448 } 449 450 if type_name, is_type_name := f.type.(Type_Name); is_type_name { 451 f.type = final_type_name(type_name, config) 452 } 453 } 454 455 case Type_Enum: 456 strip_enum_member_prefixes(&tv) 457 458 case Type_Bit_Set: 459 if type_name, is_type_name := tv.enum_decl_name.(Type_Name); is_type_name { 460 tv.enum_decl_name = final_type_name(type_name, config) 461 } 462 463 case Type_Bit_Set_Constant: 464 tv.bit_set_type_name = final_type_name(tv.bit_set_type_name, config) 465 466 case Type_Alias: 467 if type_name, is_type_name := tv.aliased_type.(Type_Name); is_type_name { 468 tv.aliased_type = final_type_name(type_name, config) 469 } 470 471 case Type_Fixed_Array: 472 if type_name, is_type_name := tv.element_type.(Type_Name); is_type_name { 473 tv.element_type = final_type_name(type_name, config) 474 } 475 476 case Type_Procedure: 477 for &p in tv.parameters { 478 p.name = ensure_name_valid(p.name) 479 480 if type_name, is_type_name := p.type.(Type_Name); is_type_name { 481 p.type = final_type_name(type_name, config) 482 } 483 } 484 485 if type_name, is_type_name := tv.result_type.(Type_Name); is_type_name { 486 tv.result_type = final_type_name(type_name, config) 487 } 488 } 489 } 490 491 for &d in decls { 492 d.name = final_decl_name(d, types, config) 493 494 switch &def in d.def { 495 case Type_Name: d.def = final_type_name(def, config) 496 case Macro_Name: d.def = final_macro_name(def, config) 497 498 case Fixed_Value: 499 case Type_Index: 500 } 501 } 502 } 503 504 override_procedure_parameter :: proc(p: ^Type_Procedure_Parameter, types: Type_List, override: string) { 505 if override == "[^]" { 506 if ptr_type, is_ptr_type := resolve_type_definition(types, p.type, Type_Pointer); is_ptr_type { 507 p.type = add_type(types, Type_Multipointer { 508 pointed_to_type = ptr_type.pointed_to_type, 509 }) 510 } 511 } else if override == "#by_ptr" { 512 if ptr_type, is_ptr_type := resolve_type_definition(types, p.type, Type_Pointer); is_ptr_type { 513 p.type = add_type(types, Type_Pointer_By_Ptr { 514 pointed_to_type = ptr_type.pointed_to_type, 515 }) 516 } 517 } else if override == "#any_int" { 518 p.any_int = true 519 } else { 520 p.type = Fixed_Value(override) 521 } 522 } 523 524 is_number :: proc(b: byte) -> bool { 525 return b >= '0' && b <= '9' 526 } 527 528 ensure_name_valid :: proc(s: string) -> string { 529 // TODO make sure this contains all Odin keywords 530 KEYWORDS :: [?]string { 531 "_bool", 532 "_b8", 533 "_b16", 534 "_b32", 535 "_b64", 536 "_int", 537 "_i8", 538 "_i16", 539 "_i32", 540 "_i64", 541 "_i128", 542 "_uint", 543 "_u8", 544 "_u16", 545 "_u32", 546 "_u64", 547 "_u128", 548 "_uintptr", 549 "_i16le", 550 "_i32le", 551 "_i64le", 552 "_i128le", 553 "_u16le", 554 "_u32le", 555 "_u64le", 556 "_u128le", 557 "_i16be", 558 "_i32be", 559 "_i64be", 560 "_i128be", 561 "_u16be", 562 "_u32be", 563 "_u64be", 564 "_u128be", 565 "_f16", 566 "_f32", 567 "_f64", 568 "_f16le", 569 "_f32le", 570 "_f64le", 571 "_f16be", 572 "_f32be", 573 "_f64be", 574 "_complex32", 575 "_complex64", 576 "_complex128", 577 "_quaternion64", 578 "_quaternion128", 579 "_quaternion256", 580 "_rune", 581 "_string", 582 "_cstring", 583 "_string16", 584 "_cstring16", 585 "_rawptr", 586 "_typeid", 587 "_any", 588 "_asm", 589 "_auto_cast", 590 "_bit_set", 591 "_break", 592 "_case", 593 "_cast", 594 "_context", 595 "_continue", 596 "_defer", 597 "_distinct", 598 "_do", 599 "_dynamic", 600 "_else", 601 "_enum", 602 "_fallthrough", 603 "_for", 604 "_foreign", 605 "_if", 606 "_import", 607 "_in", 608 "_map", 609 "_not_in", 610 "_or_else", 611 "_or_return", 612 "_package", 613 "_proc", 614 "_return", 615 "_struct", 616 "_switch", 617 "_transmute", 618 "_typeid", 619 "_union", 620 "_using", 621 "_when", 622 "_where", 623 "_matrix", 624 625 // Not keywords, but used names: 626 "_c", 627 } 628 629 for k in KEYWORDS { 630 if s == k[1:] { 631 return k 632 } 633 } 634 635 if len(s) > 0 && unicode.is_number(utf8.rune_at(s, 0)) { 636 return fmt.tprintf("_%v", s) 637 } 638 639 return s 640 } 641 642 final_decl_name :: proc(d: Decl, types: Type_List, config: Config) -> string { 643 if d.explicitly_created { 644 return d.name 645 } 646 647 if new_name, rename := config.rename[string(d.name)]; rename { 648 return new_name 649 } 650 651 _, is_proc := resolve_type_definition(types, d.def, Type_Procedure) 652 653 if is_proc { 654 return strings.trim_prefix(d.name, config.remove_function_prefix) 655 } else if d.from_macro { 656 return strings.trim_prefix(d.name, config.remove_macro_prefix) 657 } else { 658 res := strings.trim_prefix(d.name, config.remove_type_prefix) 659 res = strings.trim_suffix(res, config.remove_type_suffix) 660 661 if config.force_ada_case_types { 662 res = strings.to_ada_case(res) 663 } 664 665 return res 666 } 667 668 return d.name 669 } 670 671 final_type_name :: proc(name: Type_Name, config: Config) -> Type_Name { 672 if new_name, rename := config.rename[string(name)]; rename { 673 return Type_Name(new_name) 674 } 675 676 res := strings.trim_prefix(string(name), config.remove_type_prefix) 677 res = strings.trim_suffix(res, config.remove_type_suffix) 678 679 if config.force_ada_case_types { 680 res = strings.to_ada_case(res) 681 } 682 683 return Type_Name(res) 684 } 685 686 final_macro_name :: proc(name: Macro_Name, config: Config) -> Macro_Name { 687 return Macro_Name(strings.trim_prefix(string(name), config.remove_macro_prefix)) 688 } 689 690 // Extracts any comment at the top of the source file. These will be put above the package line in 691 // the bindings. 692 extract_top_comment :: proc(src: string) -> string { 693 src := src 694 src = strings.trim_space(src) 695 top_comment_end: int 696 in_block := false 697 on_line_comment := false 698 699 next_rune :: proc(s: string, cur: rune, cur_idx: int) -> rune { 700 next, _ := utf8.decode_rune(s[cur_idx + utf8.rune_size(cur):]) 701 return next 702 } 703 704 top_comment_loop: for i := 0; i < len(src); { 705 r, r_sz := utf8.decode_rune(src[i:]) 706 adv := r_sz 707 defer i += adv 708 709 if r_sz == 0 { 710 break 711 } 712 713 if on_line_comment { 714 if r == '\n' { 715 on_line_comment = false 716 top_comment_end = i + 1 717 } 718 } else if in_block { 719 if i + 2 >= len(src) { 720 continue 721 } 722 723 if src[i:i+2] == "*/" { 724 in_block = false 725 top_comment_end = i + 2 726 adv = 2 727 } 728 } else { 729 if i + 2 >= len(src) { 730 continue 731 } 732 733 // Only OK to skip whitespace here because `on_line_comment` etc needs to check for newlines. 734 if unicode.is_white_space(r) { 735 continue 736 } 737 738 switch src[i:i+2] { 739 case "//": 740 adv = 2 741 on_line_comment = true 742 case "/*": 743 adv = 2 744 in_block = true 745 case: 746 top_comment_end = i 747 break top_comment_loop 748 } 749 } 750 } 751 752 if top_comment_end > 0 { 753 return strings.trim_space(src[:top_comment_end]) 754 } 755 756 return "" 757 }