odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

bindgen.odin (69628B)


      1 /*
      2 Generates Odin bindings from C code.
      3 
      4 Usage:
      5 bindgen folder_with_headers_inside
      6 
      7 The folder can contain a `bindgen.sjson` file tha can be used to do overrides
      8 and configure the generation. See the examples folder for how to do that.
      9 */
     10 
     11 #+feature dynamic-literals
     12 
     13 package bindgen
     14 
     15 import "core:fmt"
     16 import "core:os"
     17 import "core:os/os2"
     18 import "core:strings"
     19 import "core:strconv"
     20 import "core:path/filepath"
     21 import "core:math/bits"
     22 import "core:encoding/json"
     23 import "core:unicode"
     24 import "core:unicode/utf8"
     25 import "base:runtime"
     26 import "core:c"
     27 import "core:slice"
     28 import vmem "core:mem/virtual"
     29 import clang "../libclang"
     30 
     31 Struct_Field :: struct {
     32 	names: [dynamic]string,
     33 	type: clang.Type,
     34 	anon_using: bool,
     35 	comment: string,
     36 	comment_before: bool,
     37 	original_line: int,
     38 }
     39 
     40 Struct :: struct {
     41 	original_name: string,
     42 	name: string,
     43 	id: string,
     44 	fields: []Struct_Field,
     45 	comment: string,
     46 	is_union: bool,
     47 	is_anon: bool,
     48 	is_forward_declare: bool,
     49 }
     50 
     51 Function_Parameter :: struct {
     52 	name: string,
     53 	cursor: clang.Cursor,
     54 }
     55 
     56 Function :: struct {
     57 	original_name: string,
     58 	name: string,
     59 	cursor: clang.Cursor,
     60 
     61 	// if non-empty, then use this will be the link name used in bindings
     62 	link_name: string,
     63 	parameters: []clang.Cursor,
     64 	comment: string,
     65 	comment_before: bool,
     66 	variadic: bool,
     67 	post_comment: string,
     68 }
     69 
     70 Enum_Member :: struct {
     71 	name: string,
     72 	value: int,
     73 	comment: string,
     74 	comment_before: bool,
     75 }
     76 
     77 Enum :: struct {
     78 	original_name: string,
     79 	name: string,
     80 	id: string,
     81 	members: []Enum_Member,
     82 	comment: string,
     83 	backing_type: clang.Type,
     84 }
     85 
     86 Typedef :: struct {
     87 	original_name: string,
     88 	name: string,
     89 	type: clang.Type,
     90 	pre_comment: string,
     91 	side_comment: string,
     92 }
     93 
     94 Macro :: struct {
     95 	original_name: string,
     96 	name: string,
     97 	tokens: []clang.Token,
     98 	is_function: bool,
     99 	has_been_evaluated: bool,
    100 	should_not_output: bool,
    101 	val: string,
    102 	comment: string,
    103 	side_comment: string,
    104 	whitespace_after_name: int,
    105 	whitespace_before_side_comment: int,
    106 }
    107 
    108 Declaration_Variant :: union {
    109 	Struct,
    110 	Function,
    111 	Enum,
    112 	Typedef,
    113 	Macro,
    114 }
    115 
    116 Declaration :: struct {
    117 	// Used for sorting the declarations. They may be added out-of-order due to macros
    118 	// coming in from a separate code path.
    119 	cursor: clang.Cursor,
    120 
    121 	// The original idx in `s.decls`. This is for tie-breaking when line is the same.
    122 	original_idx: int,
    123 	variant: Declaration_Variant,
    124 }
    125 
    126 trim_prefix :: proc(s: string, p: string) -> string {
    127 	return strings.trim_prefix(strings.trim_prefix(s, p), "_")
    128 }
    129 
    130 // NOTE: This function disposes of the clang String after converting it to an Odin string.
    131 // Be sure not to attempt to use the clang String after calling this function.
    132 clang_string_to_string :: proc(str: clang.String) -> string {
    133 	ret := strings.clone_from_cstring(clang.getCString(str))
    134 	clang.disposeString(str)
    135 	return ret
    136 }
    137 
    138 cursor_spelling :: proc(cursor: clang.Cursor) -> string {
    139 	return clang_string_to_string(clang.getCursorSpelling(cursor))
    140 }
    141 
    142 cursor_usr :: proc(cursor: clang.Cursor) -> string {
    143 	return clang_string_to_string(clang.getCursorUSR(cursor))
    144 }
    145 
    146 comment_text :: proc(cursor: clang.Cursor) -> string {
    147 	return clang_string_to_string(clang.Cursor_getRawCommentText(cursor))
    148 }
    149 
    150 type_spelling :: proc(type: clang.Type) -> string {
    151 	return clang_string_to_string(clang.getTypeSpelling(type))
    152 }
    153 
    154 token_string :: proc(translation_unit: clang.Translation_Unit, token: clang.Token) -> string {
    155 	return clang_string_to_string(clang.getTokenSpelling(translation_unit, token))
    156 }
    157 
    158 // Put any built in c typedefs into here to have them converted properly.
    159 c_typedef_types := map[string]string {
    160 	"uint8_t"  = "u8",
    161 	"int8_t"   = "i8",
    162 	"uint16_t" = "u16",
    163 	"int16_t"  = "i16",
    164 	"uint32_t" = "u32",
    165 	"int32_t"  = "i32",
    166 	"uint64_t" = "u64",
    167 	"int64_t"  = "i64",
    168 
    169 	"int_least8_t"   = "i8",
    170 	"uint_least8_t"  = "u8",
    171 	"int_least16_t"  = "i16",
    172 	"uint_least16_t" = "u16",
    173 	"int_least32_t"  = "i32",
    174 	"uint_least32_t" = "u32",
    175 	"int_least64_t"  = "i64",
    176 	"uint_least64_t" = "u64",
    177 
    178 	"int_fast8_t"   = "i8",
    179 	"uint_fast8_t"  = "u8",
    180 	"int_fast32_t"  = "i32",
    181 	"uint_fast32_t" = "u32",
    182 	"int_fast64_t"  = "i64",
    183 	"uint_fast64_t" = "u64",
    184 }
    185 
    186 // These types are either platform dependent or the type provides the developer with extra context for its use.
    187 c_type_mapping := map[string]string {
    188 	// Platform dependent
    189 	"long"          = "c.long",
    190 	"unsigned long" = "c.ulong",
    191 	"int_fast16_t"  = "c.int_fast16_t",
    192 	"uint_fast16_t" = "c.uint_fast16_t",
    193 
    194 	// Size & wchar
    195 	"size_t"  = "c.size_t",
    196 	"ssize_t" = "c.ssize_t",
    197 	"wchar_t" = "c.wchar_t",
    198 
    199 	// ptr types
    200 	"intptr_t"  = "c.intptr_t",
    201 	"uintptr_t" = "c.uintptr_t",
    202 	"ptrdiff_t" = "c.ptrdiff_t",
    203 
    204 	// intmax types
    205 	"intmax_t"  = "c.intmax_t",
    206 	"uintmax_t" = "c.uintmax_t",
    207 
    208 	// va_list
    209 	"va_list" = "c.va_list",
    210 }
    211 
    212 is_c_type :: proc(type: clang.Type) -> bool {
    213 	return type_spelling(type) in c_type_mapping
    214 }
    215 
    216 // Types that would need "import 'core:sys/posix'".
    217 // Please add and send in a Pull Request if you needed to add anything here!
    218 posix_type_mapping := map[string]string {
    219 	"dev_t"      = "posix.dev_t",
    220 	"blkcnt_t"   = "posix.blkcnt_t",
    221 	"blksize_t"  = "posix.blksize_t",
    222 	"clock_t"    = "posix.clock_t",
    223 	"clockid_t"  = "posix.clockid_t",
    224 	"fsblkcnt_t" = "posix.fsblkcnt_t",
    225 	"off_t"      = "posix.off_t",
    226 	"gid_t"      = "posix.gid_t",
    227 	"pid_t"      = "posix.pid_t",
    228 	"timespec"   = "posix.timespec",
    229 }
    230 
    231 is_posix_type :: proc(type: clang.Type) -> bool {
    232 	return type_spelling(type) in posix_type_mapping
    233 }
    234 
    235 // Types that would need `import "core:c/libc"`. 
    236 // Please add and send in a Pull Request if you needed to add anything here!
    237 libc_type_mapping := map[string]string {
    238 	"time_t"       = "libc.time_t",
    239 }
    240 
    241 is_libc_type :: proc(type: clang.Type) -> bool {
    242 	return type_spelling(type) in libc_type_mapping
    243 }
    244 
    245 translate_name :: proc(s: ^Gen_State, name: string) -> string {
    246 	ret: string
    247 	if replacement, has_replacement := s.rename[name]; has_replacement {
    248 		ret = replacement
    249 	} else {
    250 		ret = trim_prefix(name, s.remove_type_prefix)
    251 
    252 		if s.force_ada_case_types {
    253 			ret = strings.to_ada_case(ret)
    254 		}
    255 	}
    256 	return ret
    257 }
    258 
    259 parse_nonfunction_type :: proc(s: ^Gen_State, type: clang.Type, opts: Type_Parsing_Options) -> (string, bool) {
    260 	type_string := type_spelling(type)
    261 	if c_type, exists := c_type_mapping[type_string]; exists {
    262 		return c_type, false
    263 	}
    264 	if posix_type, exists := posix_type_mapping[type_string]; exists {
    265 		return posix_type, false
    266 	}
    267 	if libc_type, exists := libc_type_mapping[type_string]; exists {
    268 		return libc_type, false
    269 	}
    270 
    271 	#partial switch type.kind {
    272 	case .Invalid, .Unexposed, .Void:
    273 		return "", false
    274 	case .Long, .ULong, .WChar:
    275 		// We handle these with c_type_mapping
    276 		return "", false
    277 	case .Bool:
    278 		return "bool", false
    279 	case .Char_U, .UChar:
    280 		return "u8", false
    281 	case .UShort:
    282 		return "u16", false
    283 	case .UInt:
    284 		return "u32", false
    285 	case .ULongLong:
    286 		return "u64", false
    287 	case .UInt128:
    288 		return "u128", false
    289 	case .Char_S, .SChar:
    290 		return "i8", false
    291 	case .Short:
    292 		return "i16", false
    293 	case .Int:
    294 		return "i32", false
    295 	case .LongLong:
    296 		return "i64", false
    297 	case .Int128:
    298 		return "i128", false
    299 	case .Float:
    300 		return "f32", false
    301 	case .Double, .LongDouble:
    302 		return "f64", false
    303 	case .NullPtr:
    304 		return "rawptr", false
    305 	case .Complex:
    306 		#partial switch clang.getElementType(type).kind {
    307 		case .Float:
    308 			return "complex64", false
    309 		case .Double, .LongDouble:
    310 			return "complex128", false
    311 		}
    312 	case .Pointer:
    313 		pointee_string, _ := parse_type(s, clang.getPointeeType(type), opts - {.Pointer_To_Array, .By_Pointer})
    314 		if pointee_string == "" {
    315 			return "rawptr", false
    316 		}
    317 
    318 		builder := strings.builder_make()
    319 
    320 		if .Pointer_To_Array in opts {
    321 			strings.write_string(&builder, "[^]")
    322 		} else if .By_Pointer in opts {
    323 			// We need to handle this outside of the type parsing because it needs to go infront of the parameter name.
    324 			// strings.write_string(&builder, "#by_ptr ")
    325 		} else {
    326 			if pointee_string == "i8" {
    327 				return "cstring", false
    328 			} else if pointee_string == "cstring" {
    329 				return "[^]cstring", false
    330 			}
    331 			strings.write_byte(&builder, '^')
    332 		}
    333 
    334 		strings.write_string(&builder, pointee_string)
    335 		return strings.to_string(builder), .By_Pointer in opts
    336 	case .Record, .Enum, .Typedef:
    337 		return translate_name(s, cursor_spelling(clang.getTypeDeclaration(type))), false
    338 	case .ConstantArray:
    339 		builder := strings.builder_make()
    340 
    341 		strings.write_byte(&builder, '[')
    342 
    343 		str_conv_buf: [20]byte // 20 == base_10_digit_count(c.SIZE_MAX)
    344 		strings.write_string(&builder, strconv.write_int(str_conv_buf[:], i64(clang.getArraySize(type)), 10))
    345 
    346 		strings.write_byte(&builder, ']')
    347 		str, _ := parse_type(s, clang.getArrayElementType(type), opts)
    348 		strings.write_string(&builder, str)
    349 		return strings.to_string(builder), true
    350 	case .IncompleteArray, .VariableArray:
    351 		builder := strings.builder_make()
    352 		strings.write_string(&builder, "[^]")
    353 		str, _ := parse_type(s, clang.getArrayElementType(type), opts)
    354 		strings.write_string(&builder, str)
    355 		return strings.to_string(builder), false
    356 	case .Elaborated:
    357 		elaborated_type := clang.Type_getNamedType(type)
    358 		#partial switch elaborated_type.kind {
    359 		case .Record, .Enum, .FunctionNoProto, .FunctionProto:
    360 			return translate_name(s, cursor_spelling(clang.getTypeDeclaration(type))), false
    361 		case .Typedef:
    362 			cursor_decl := clang.getTypeDeclaration(elaborated_type)
    363 			cursor_name := cursor_spelling(cursor_decl)
    364 			if replacement, exists := c_typedef_types[cursor_name]; exists {
    365 				return replacement, false
    366 			}
    367 			if clang.getTypedefDeclUnderlyingType(cursor_decl).kind == .ConstantArray {
    368 				return translate_name(s, cursor_name), true
    369 			}
    370 			return translate_name(s, cursor_name), false
    371 		}
    372 		return parse_type(s, elaborated_type, opts)
    373 	}
    374 	// If we get here then we need to add a new case.
    375 	panic("Unreachable!")
    376 }
    377 
    378 parse_function_type :: proc(s: ^Gen_State, type: clang.Type, opts: Type_Parsing_Options) -> (string, bool) {
    379 	builder := strings.builder_make()
    380 	strings.write_string(&builder, "proc ")
    381 	#partial switch clang.getFunctionTypeCallingConv(type) {
    382 	case .X86StdCall:
    383 		strings.write_string(&builder, "\"stdcall\" (")
    384 	case .X86FastCall:
    385 		strings.write_string(&builder, "\"fastcall\" (")
    386 	case:
    387 		strings.write_string(&builder, "\"c\" (")
    388 	}
    389 
    390 	for i: u32 = 0; i < u32(clang.getNumArgTypes(type)); i += 1 {
    391 		if i != 0 {
    392 			strings.write_string(&builder, ", ")
    393 		}
    394 		type_string, by_ptr := parse_type(s, clang.getArgType(type, i), nil)
    395 		if by_ptr {
    396 			strings.write_string(&builder, "#by_ptr ")
    397 		}
    398 		strings.write_string(&builder, type_string)
    399 	}
    400 
    401 	if bool(clang.isFunctionTypeVariadic(type)) {
    402 		if clang.getNumArgTypes(type) > 0 {
    403 			strings.write_string(&builder, ", ")
    404 		}
    405 
    406 		strings.write_string(&builder, "#c_vararg ..any")
    407 	}
    408 
    409 	strings.write_byte(&builder, ')')
    410 
    411 	if return_type := clang.getResultType(type); return_type.kind != .Void {
    412 		strings.write_string(&builder, " -> ")
    413 		str, _ := parse_type(s, return_type, nil)
    414 		strings.write_string(&builder, str)
    415 	}
    416 
    417 	return strings.to_string(builder), false
    418 }
    419 
    420 Type_Parsing_Option :: enum {
    421 	Pointer_To_Array,
    422 	By_Pointer,
    423 }
    424 
    425 Type_Parsing_Options :: bit_set[Type_Parsing_Option]
    426 
    427 parse_type :: proc(s: ^Gen_State, type: clang.Type, opts: Type_Parsing_Options) -> (string, bool) {
    428 	#partial switch type.kind {
    429 	case .FunctionProto, .FunctionNoProto:
    430 		return parse_function_type(s, type, opts)
    431 	case .Pointer:
    432 		#partial switch pointee_type := clang.getPointeeType(type); pointee_type.kind {
    433 		case .FunctionProto, .FunctionNoProto:
    434 			return parse_function_type(s, pointee_type, opts)
    435 		case .Elaborated:
    436 			if elaborated_type := clang.Type_getNamedType(pointee_type); elaborated_type.kind == .Typedef {
    437 				#partial switch clang.getTypedefDeclUnderlyingType(clang.getTypeDeclaration(elaborated_type)).kind {
    438 				case .FunctionNoProto, .FunctionProto:
    439 					return translate_name(s, cursor_spelling(clang.getTypeDeclaration(elaborated_type))), false
    440 				}
    441 			}
    442 		}
    443 	}
    444 	return parse_nonfunction_type(s, type, opts)
    445 }
    446 
    447 // Only used for parsing types in macros
    448 translate_type_string :: proc(s: ^Gen_State, t: string) -> string {
    449 	if type, exists := c_type_mapping[t]; exists {
    450 		return type
    451 	}
    452 
    453 	if replacement, exists := c_typedef_types[t]; exists {
    454 		return replacement
    455 	}
    456 
    457 	c_types := map[string]string {
    458 		"char" = "i8",
    459 		"short" = "i16",
    460 		"int" = "i32",
    461 		"long long" = "i64",
    462 
    463 		"unsigned char" = "u8",
    464 		"unsigned short" = "u16",
    465 		"unsigned int" = "u32",
    466 		"unsigned long long" = "u64",
    467 
    468 		"float" = "f32",
    469 		"double" = "f64",
    470 
    471 		"bool" = "bool",
    472 	}
    473 	if type, exists := c_types[t]; exists {
    474 		return type
    475 	}
    476 
    477 	// Tokenize the type and skip over some parameter type keywords that have no meaning in Odin.
    478 	type_tokens: [dynamic]string
    479 	token_start := 0
    480 
    481 	t := t
    482 	for s, idx in t {
    483 		tok: string
    484 
    485 		if strings.is_space(s) {
    486 			tok = t[token_start:idx]
    487 			token_start = idx + utf8.rune_size(s)
    488 		} else if s == '*' || s == '(' || s == ')' {
    489 			// Any type with a *, ( or ) is non trivial and shouldn't be used in a macro.
    490 			return ""
    491 		} else if idx == len(t) - 1{
    492 			tok = t[token_start:idx + 1]
    493 		}
    494 
    495 		if len(tok) > 0 {
    496 			if tok == "const" {
    497 				continue
    498 			}
    499 
    500 			if tok == "struct" || tok == "enum" {
    501 				return ""
    502 			}
    503 
    504 			append(&type_tokens, tok)
    505 		}
    506 	}
    507 
    508 	t = strings.join(type_tokens[:], " ")
    509 
    510 	// A hack to check if something is an array of arrays. Then it will appear as `(*)[3] etc. But
    511 	// the code above removes the `*`, so we check for `( )[`
    512 	t_original := t
    513 	array_start := strings.index(t_original, "[")
    514 	array_end := strings.last_index(t_original, "]")
    515 
    516 	if array_start != -1 {
    517 		t = t[:array_start]
    518 	}
    519 
    520 	// check maps against this in case the header has a type which is exactly [prefix][mapped c type]
    521 	t_prefixed := strings.trim_space(t)
    522 	if t != s.remove_type_prefix {
    523 		t = trim_prefix(t, s.remove_type_prefix)
    524 	}
    525 
    526 	t = strings.trim_space(t)
    527 
    528 	if name_c, exists_c := c_type_mapping[t_prefixed]; exists_c {
    529 		t = name_c
    530 	} else if name_c_2, exists_c_2 := c_types[t_prefixed]; exists_c_2 {
    531 		t = name_c_2
    532 	} else if name_libc, exists_libc := libc_type_mapping[t_prefixed]; exists_libc {
    533 		t = name_libc
    534 	} else if name_posix, exists_posix := posix_type_mapping[t_prefixed]; exists_posix {
    535 		t = name_posix
    536 	} else if rename, exists := s.rename[t_prefixed]; exists {
    537 		t = vet_name(rename)
    538 	} else {
    539 		t = translate_name(s, t)
    540 		if t not_in s.created_types {
    541 			return ""
    542 		}
    543 	}
    544 
    545 	b := strings.builder_make()
    546 
    547 	if array_start != -1 {
    548 		strings.write_string(&b, t_original[array_start:array_end + 1])
    549 	}
    550 
    551 	strings.write_string(&b, t)
    552 	return strings.to_string(b)
    553 }
    554 
    555 // Keywords in Odin that don't exist in C. The `_` is there so we can return it
    556 // without allocating memory (we compare to the slice [1:])
    557 VET_NAMES :: [?]string {
    558 	"_rune",
    559 	"_import",
    560 	"_foreign",
    561 	"_package",
    562 	"_typeid",
    563 	"_when",
    564 	"_where",
    565 	"_in",
    566 	"_not_in",
    567 	"_fallthrough",
    568 	"_defer",
    569 	"_proc",
    570 	"_bit_set",
    571 	"_bit_field",
    572 	"_map",
    573 	"_dynamic",
    574 	"_auto_cast",
    575 	"_cast",
    576 	"_transmute",
    577 	"_distinct",
    578 	"_using",
    579 	"_context",
    580 	"_or_else",
    581 	"_or_return",
    582 	"_or_break",
    583 	"_or_continue",
    584 	"_asm",
    585 	"_inline",
    586 	"_no_inline",
    587 	"_matrix",
    588 	"_string",
    589 
    590 	// Because we import these three
    591 	"_c",
    592 	"_libc",
    593 	"_posix",
    594 }
    595 
    596 vet_name :: proc(s: string) -> string {
    597 	for v in VET_NAMES {
    598 		if s == v[1:] {
    599 			return v
    600 		}
    601 	}
    602 
    603 	return s
    604 }
    605 
    606 add_to_set :: proc(s: ^map[$T]struct{}, v: T) {
    607 	s[v] = {}
    608 }
    609 
    610 find_comment_at_line_end :: proc(str: string) -> (string, int) {
    611 	space_before_comment: int
    612 	comment_start: int
    613 	block_comment: bool
    614 
    615 	for c, i in str {
    616 		if c == ' ' {
    617 			space_before_comment += 1
    618 		} else if c == '/' && i + 1 < len(str) && str[i + 1] == '/' {
    619 			comment_start = i
    620 			break
    621 		} else if c == '/' && i + 1 < len(str) && str[i + 1] == '*' {
    622 			comment_start = i
    623 			block_comment = true
    624 			break
    625 		} else if c == '\n' {
    626 			break
    627 		} else {
    628 			space_before_comment = 0
    629 		}
    630 	}
    631 
    632 	if comment_start == 0 {
    633 		return "", 0
    634 	}
    635 
    636 	if block_comment {
    637 		from_start := str[comment_start:]
    638 
    639 		for c, i in from_start {
    640 			if c == '*' && i < len(from_start) - 1 && from_start[i + 1] == '/' {
    641 				return from_start[:i+2], space_before_comment
    642 			}
    643 		}
    644 	} else {
    645 		from_start := str[comment_start:]
    646 
    647 		for c, i in from_start {
    648 			if c == '\n' {
    649 				return from_start[:i], space_before_comment
    650 			}
    651 		}
    652 	}
    653 
    654 	return "", 0
    655 }
    656 
    657 dump_ast :: proc(root_cursor: clang.Cursor, source_file: clang.File, out_file: string) {
    658     indent :: proc(file: ^os2.File, indent_level: u32) {
    659         for _ in 0 ..< indent_level {
    660             os2.write_string(file, "  ")
    661         }
    662     }
    663 
    664     visitor_proc: clang.Cursor_Visitor : proc "c" (
    665         cursor, parent: clang.Cursor,
    666         state: clang.Client_Data,
    667     ) -> clang.Child_Visit_Result {
    668         context = runtime.default_context()
    669         data := (^Data)(state)
    670 
    671         file: clang.File
    672         clang.getExpansionLocation(clang.getCursorLocation(cursor), &file, nil, nil, nil)
    673         if !bool(clang.File_isEqual(file, data.clang_file)) {
    674             return .Continue
    675         }
    676 
    677         indent(data.file, data.indent - 1)
    678         os2.write_string(data.file, fmt.tprintln("- Visiting:", cursor_spelling(cursor)))
    679 
    680         indent(data.file, data.indent)
    681         os2.write_string(data.file, fmt.tprintln("Parent:", cursor_spelling(parent)))
    682 
    683         indent(data.file, data.indent)
    684         os2.write_string(data.file, fmt.tprintln("Kind:", cursor.kind))
    685 
    686         indent(data.file, data.indent)
    687         os2.write_string(data.file, fmt.tprintln("TypeKind:", clang.getCursorType(cursor).kind))
    688 
    689         indent(data.file, data.indent)
    690         os2.write_string(data.file, "Children:\n")
    691         
    692         new_state := Data {
    693             file       = data.file,
    694             clang_file = data.clang_file,
    695             indent     = data.indent + 1,
    696         }
    697         clang.visitChildren(cursor, visitor_proc, &new_state)
    698 
    699         return .Continue
    700     }
    701 
    702 	file, _ := os2.open(out_file, flags = {.Create, .Write, .Trunc})
    703     os2.write_string(file, fmt.tprintln("File:", clang_string_to_string(clang.getFileName(source_file))))
    704     os2.write_string(file, "Cursors:\n")
    705 
    706     Data :: struct {
    707         file:       ^os2.File,
    708         clang_file: clang.File,
    709         indent:     u32,
    710     }
    711 	userData := Data {
    712 		file       = file,
    713 		clang_file = source_file,
    714 		indent     = 1,
    715 	}
    716 
    717 	clang.visitChildren(root_cursor, visitor_proc, &userData)
    718 }
    719 
    720 fp :: fmt.fprint
    721 fpln :: fmt.fprintln
    722 fpf :: fmt.fprintf
    723 fpfln :: fmt.fprintfln
    724 
    725 Config :: struct {
    726 	inputs: []string,
    727 	ignore_inputs: []string,
    728 	output_folder: string,
    729 	package_name: string,
    730 	required_prefix: string,
    731 
    732 	// deprecated: use remove_xxx_prefix
    733 	remove_prefix: string,
    734 	remove_type_prefix: string,
    735 	remove_function_prefix: string,
    736 	remove_macro_prefix: string,
    737 	import_lib: string,
    738 	imports_file: string,
    739 	clang_include_paths: []string,
    740 	clang_defines: map[string]string,
    741 	force_ada_case_types: bool,
    742 	opaque_types: []string,
    743 	rename: map[string]string,
    744 	remove_macros: []string,
    745 	debug_dump_ast: bool,
    746 
    747 	// deprecated: use rename
    748 	rename_types: map[string]string,
    749 	type_overrides: map[string]string,
    750 	struct_field_overrides: map[string]string,
    751 	procedure_type_overrides: map[string]string,
    752 	bit_setify: map[string]string,
    753 	inject_before: map[string]string,
    754 }
    755 
    756 Gen_State :: struct {
    757 	using config: Config,
    758 	file: clang.File,
    759 	source: string,
    760 	decls: [dynamic]Declaration,
    761 	macro_defines: map[string]int,
    762 	symbol_indices: map[string]int,
    763 	typedefs: map[string]string,
    764 	created_symbols: map[string]struct {},
    765 	type_is_proc: map[string]struct {},
    766 	opaque_type_lookup: map[string]struct {},
    767 	remove_macros_lookup: map[string]struct {},
    768 	created_types: map[string]struct {},
    769 	needs_import_c: bool,
    770 	needs_import_libc: bool,
    771 	needs_import_posix: bool,
    772 }
    773 
    774 gen :: proc(input: string, c: Config) {
    775 	// Everything allocated within this call to `gen` is allocated on a single
    776 	// arena, which is destroyed when this procedure ends.
    777 
    778 	gen_arena: vmem.Arena
    779 	defer vmem.arena_destroy(&gen_arena)
    780 	context.allocator = vmem.arena_allocator(&gen_arena)
    781 	context.temp_allocator = vmem.arena_allocator(&gen_arena)
    782 
    783 	s := Gen_State {
    784 		config = c,
    785 	}
    786 
    787 	for ot in c.opaque_types {
    788 		// For quick lookup
    789 		add_to_set(&s.opaque_type_lookup, ot)
    790 	}
    791 
    792 	for m in c.remove_macros {
    793 		// For quick lookup
    794 		add_to_set(&s.remove_macros_lookup, m)
    795 	}
    796 
    797 	//
    798 	// Parse file using libclang and produce an AST.
    799 	//
    800 
    801 	clang_args := make([]cstring, 1 + len(c.clang_include_paths) + len(c.clang_defines))
    802 	clang_args[0] = "-fparse-all-comments"
    803 
    804 	{
    805 		index := 1
    806 		for &include in c.clang_include_paths {
    807 			clang_args[index] = fmt.ctprintf("-I%v", include)
    808 			index += 1
    809 		}
    810 
    811 		for k, v in c.clang_defines {
    812 			clang_args[index] = fmt.ctprintf("-D%s=%s", k, v)
    813 			index += 1
    814 		}
    815 	}
    816 
    817 	idx := clang.createIndex(1, 0)
    818 	unit: clang.Translation_Unit
    819 
    820 	input_cstring := strings.clone_to_cstring(input)
    821 
    822 	// Keep macros, skip function bodies, and keep going on errors.
    823 	options: clang.Translation_Unit_Flags = {
    824 		.DetailedPreprocessingRecord,
    825 		.SkipFunctionBodies,
    826 		.KeepGoing,
    827 	}
    828 	err := clang.parseTranslationUnit2(
    829 		idx,
    830 		input_cstring,
    831 		raw_data(clang_args),
    832 		i32(len(clang_args)),
    833 		nil,
    834 		0,
    835 		options,
    836 		&unit,
    837 	)
    838 	if err != .Success {
    839 		fmt.panicf("Failed to parse translation unit for %s. Error code: %i", input, err)
    840 	}
    841 
    842 	s.file = clang.getFile(unit, input_cstring)
    843 
    844 	source_data, source_data_ok := os.read_entire_file(input)
    845 	fmt.ensuref(source_data_ok, "Failed reading source file: %v", input)
    846 	s.source = string(source_data)
    847 
    848 	cursor_location :: proc(cursor: clang.Cursor, file: ^clang.File = nil, offset: ^u32 = nil) -> (line: u32) {
    849 		clang.getExpansionLocation(clang.getCursorLocation(cursor), file, &line, nil, offset)
    850 		return
    851 	}
    852 
    853 	comment_location :: proc(cursor: clang.Cursor) -> (line: u32) {
    854 		clang.getExpansionLocation(clang.getRangeStart(clang.Cursor_getCommentRange(cursor)), nil, &line, nil, nil)
    855 		return
    856 	}
    857 
    858 	vet_type :: proc(s: ^Gen_State, type: clang.Type) {
    859 		type := type
    860 		for type.kind == .Pointer {
    861 			type = clang.getPointeeType(type)
    862 		}
    863 
    864 		if is_c_type(type) {
    865 			s.needs_import_c = true
    866 		} else if is_libc_type(type) {
    867 			s.needs_import_libc = true
    868 		} else if is_posix_type(type) {
    869 			s.needs_import_posix = true
    870 		}
    871 	}
    872 
    873 	parse_function_decl :: proc(state: ^Gen_State, cursor: clang.Cursor) -> Function {
    874 		// We could probably make use of `clang.Type` here and not store a string.
    875 		// This is easier to implement for now. We can make improvments later.
    876 		return_type := clang.getCursorResultType(cursor)
    877 		vet_type(state, return_type)
    878 
    879 		out_params: [dynamic]clang.Cursor
    880 
    881 		for i in 0 ..< clang.Cursor_getNumArguments(cursor) {
    882 			param_cursor := clang.Cursor_getArgument(cursor, u32(i))
    883 			#partial switch param_kind := clang.getCursorKind(param_cursor); param_kind {
    884 			case .ParmDecl:
    885 				vet_type(state, clang.getCursorType(param_cursor))
    886 				append(&out_params, param_cursor)
    887 			case:
    888 				// For debugging purposes.
    889 				fmt.printfln("Unexpected cursor kind for parameter: %v", param_kind)
    890 			}
    891 		}
    892 
    893 		offset: u32
    894 		line := cursor_location(cursor, nil, &offset)
    895 		side_comment: string
    896 		translation_unit := clang.Cursor_getTranslationUnit(cursor)
    897 		for true {
    898 			token := clang.getToken(translation_unit, clang.getLocationForOffset(translation_unit, state.file, offset))
    899 			if token == nil {
    900 				break
    901 			}
    902 
    903 			defer clang.disposeTokens(translation_unit, token, 1)
    904 			tline: u32
    905 			clang.getFileLocation(clang.getTokenLocation(translation_unit, token[0]), nil, &tline, nil, &offset)
    906 			if tline != line {
    907 				break
    908 			}
    909 			
    910 			token_string := token_string(translation_unit, token[0])
    911 			if clang.getTokenKind(token[0]) == .Comment {
    912 				side_comment = token_string
    913 				break
    914 			}
    915 
    916 			offset += u32(len(token_string))
    917 		}
    918 
    919 		comment := comment_text(cursor)
    920 		cline := comment_location(cursor)
    921 
    922 		return Function {
    923 			original_name = cursor_spelling(cursor),
    924 			parameters = out_params[:],
    925 			cursor = cursor,
    926 			comment = comment,
    927 			comment_before = comment == "" ? false : cline != line,
    928 			post_comment = side_comment,
    929 			variadic = bool(clang.Cursor_isVariadic(cursor)),
    930 		}
    931 	}
    932 
    933 	parse_record_decl :: proc(state: ^Gen_State, cursor: clang.Cursor) -> Struct {
    934 		child_proc: clang.Cursor_Visitor : proc "c" (
    935 			cursor, parent: clang.Cursor,
    936 			data: clang.Client_Data,
    937 		) -> clang.Child_Visit_Result {
    938 			context = runtime.default_context()
    939 			data := (^Data)(data)
    940 
    941 			line: u32
    942 			clang.getExpansionLocation(clang.getCursorLocation(cursor), nil, &line, nil, nil)
    943 
    944 			cline := comment_location(cursor)
    945 
    946 			comment := comment_text(cursor)
    947 			comment_before := comment == "" ? false : cline != line
    948 
    949 			#partial switch kind := clang.getCursorKind(cursor); kind {
    950 			case .FieldDecl:
    951 				type := clang.getCursorType(cursor)
    952 				field_name := cursor_spelling(cursor)
    953 				if field_name == "" {
    954 					field_name = "_"
    955 				}
    956 
    957 				if prev_idx := len(data.out_fields) - 1; prev_idx >= 0 && bool(clang.equalTypes(data.out_fields[prev_idx].type, type)) \
    958 				  && data.out_fields[prev_idx].original_line == int(line) {
    959 					append(&data.out_fields[len(data.out_fields) - 1].names, field_name)
    960 				} else {
    961 					vet_type(data.state, type)
    962 					append(&data.out_fields, Struct_Field {
    963 						names = [dynamic]string {field_name},
    964 						type = type,
    965 						anon_using = false,
    966 						comment = comment,
    967 						comment_before = comment_before,
    968 						original_line = int(line),
    969 					})
    970 				}
    971 			case .StructDecl, .UnionDecl:
    972 				// This is a "forward declaration" of a struct directly on a field. We output a
    973 				// named opaque type for it. Not sure if it is the best idea, but it seems to "just work".
    974 				append(&data.state.decls, Declaration {
    975 					cursor = cursor,
    976 					original_idx = len(data.state.decls),
    977 					variant = parse_record_decl(data.state, cursor),
    978 				})
    979 
    980 				data.state.opaque_type_lookup[cursor_spelling(cursor)] = {}
    981 
    982 				if bool(clang.Cursor_isAnonymousRecordDecl(cursor)) {
    983 					append(&data.out_fields, Struct_Field {
    984 						names = [dynamic]string {cursor_spelling(cursor)},
    985 						type = clang.getCursorType(cursor),
    986 						anon_using = true,
    987 						comment = comment,
    988 						comment_before = comment_before,
    989 						original_line = int(line),
    990 					})
    991 				}
    992 			case:
    993 				// For debugging purposes.
    994 				fmt.printf("Unexpected cursor kind for field: %v, name: %s\n", kind, cursor_spelling(cursor))
    995 			}
    996 			return .Continue
    997 		}
    998 
    999 		Data :: struct {
   1000 			state: ^Gen_State,
   1001 			out_fields: [dynamic]Struct_Field,
   1002 		}
   1003 
   1004 		data: Data = {
   1005 			state = state,
   1006 			out_fields = {},
   1007 		}
   1008 
   1009 		clang.visitChildren(cursor, child_proc, &data)
   1010 
   1011 		return {
   1012 			original_name = cursor_spelling(cursor),
   1013 			id = cursor_usr(cursor),
   1014 			fields = data.out_fields[:],
   1015 			comment = comment_text(cursor),
   1016 			is_union = clang.getCursorKind(cursor) == .UnionDecl,
   1017 			is_anon = bool(clang.Cursor_isAnonymous(cursor)),
   1018 			is_forward_declare = !bool(clang.isCursorDefinition(cursor)),
   1019 		}
   1020 	}
   1021 
   1022 	parse_typedef_decl :: proc(state: ^Gen_State, cursor: clang.Cursor) -> Typedef {
   1023 		type := clang.getTypedefDeclUnderlyingType(cursor)
   1024 		vet_type(state, type)
   1025 
   1026 		source_range := clang.getCursorExtent(cursor)
   1027 		start := clang.getRangeStart(source_range)
   1028 		start_offset: c.uint
   1029 		clang.getExpansionLocation(start, &state.file, nil, nil, &start_offset)
   1030 		side_comment, _ := find_comment_at_line_end(state.source[start_offset:])
   1031 
   1032 		return {
   1033 			original_name = cursor_spelling(cursor),
   1034 			type = type,
   1035 			pre_comment = comment_text(cursor),
   1036 			side_comment = side_comment,
   1037 		}
   1038 	}
   1039 
   1040 	parse_enum_decl :: proc(state: ^Gen_State, cursor: clang.Cursor) -> Enum {
   1041 		out_members: [dynamic]Enum_Member
   1042 
   1043 		backing_type := clang.getEnumDeclIntegerType(cursor)
   1044 		vet_type(state, backing_type)
   1045 
   1046 		child_proc: clang.Cursor_Visitor : proc "c" (
   1047 			cursor, parent: clang.Cursor,
   1048 			data: clang.Client_Data,
   1049 		) -> clang.Child_Visit_Result {
   1050 			context = runtime.default_context()
   1051 			data := (^Data)(data)
   1052 
   1053 			#partial switch kind := clang.getCursorKind(cursor); kind {
   1054 			case .EnumConstantDecl:
   1055 				comment := comment_text(cursor)
   1056 				comment_before := comment == "" ? false : comment_location(cursor) != cursor_location(cursor)
   1057 
   1058 				append(data.out_members, Enum_Member {
   1059 					name = cursor_spelling(cursor),
   1060 					value = data.is_unsigned_type ? (int)(clang.getEnumConstantDeclUnsignedValue(cursor)) : (int)(clang.getEnumConstantDeclValue(cursor)),
   1061 					comment = comment,
   1062 					comment_before = comment_before,
   1063 				})
   1064 			case:
   1065 				// For debugging purposes.
   1066 				fmt.println("Unexpected cursor kind for enum member:", kind)
   1067 			}
   1068 
   1069 			return .Continue
   1070 		}
   1071 
   1072 		Data :: struct {
   1073 			is_unsigned_type: bool,
   1074 			out_members:      ^[dynamic]Enum_Member,
   1075 		}
   1076 
   1077 		clang.visitChildren(cursor, child_proc, &Data {
   1078 			is_unsigned_type = backing_type.kind >= .Char_U && backing_type.kind <= .UInt128,
   1079 			out_members = &out_members,
   1080 		})
   1081 
   1082 		return {
   1083 			original_name = bool(clang.Cursor_isAnonymous(cursor)) ? "" : cursor_spelling(cursor),
   1084 			id = cursor_usr(cursor),
   1085 			comment = comment_text(cursor),
   1086 			members = out_members[:],
   1087 			backing_type = backing_type,
   1088 		}
   1089 	}
   1090 
   1091 	parse_macro_decl :: proc(state: ^Gen_State, cursor: clang.Cursor) -> Macro {
   1092 		translation_unit := clang.Cursor_getTranslationUnit(cursor)
   1093 		source_range := clang.getCursorExtent(cursor)
   1094 		
   1095 		whitespace_after_name: int
   1096 		comment: string
   1097 		side_comment: string
   1098 		side_comment_align_whitespace: int
   1099 		{
   1100 			start := clang.getRangeStart(source_range)
   1101 			start_offset: c.uint
   1102 			clang.getExpansionLocation(start, &state.file, nil, nil, &start_offset)
   1103 			end := clang.getRangeEnd(source_range)
   1104 			end_offset: c.uint
   1105 			clang.getExpansionLocation(end, &state.file, nil, nil, &end_offset)
   1106 			macro_source := state.source[start_offset:end_offset]
   1107 
   1108 			//
   1109 			// Figure out spacing between name and value
   1110 			//
   1111 			first_space_seen := false
   1112 
   1113 			for c in macro_source {
   1114 				if unicode.is_white_space(c) {
   1115 					if !first_space_seen {
   1116 						first_space_seen = true
   1117 					}
   1118 
   1119 					whitespace_after_name += 1
   1120 				} else {
   1121 					if first_space_seen {
   1122 						break
   1123 					}
   1124 				}
   1125 			}
   1126 
   1127 			//
   1128 			// Figure out comments at the end of line
   1129 			//
   1130 			side_comment, side_comment_align_whitespace = find_comment_at_line_end(state.source[start_offset:])
   1131 
   1132 			//
   1133 			// Figure out comments before the macro
   1134 			//
   1135 
   1136 			{
   1137 				Find_Comment_State :: enum {
   1138 					Looking_For_Start,
   1139 					Looking_For_Comment,
   1140 					Looking_For_Single_Line_Start,
   1141 					Verifying_Single_Line,
   1142 					Inside_Block_Comment,
   1143 				}
   1144 				src := state.source
   1145 				find_state: Find_Comment_State
   1146 				comment_start := -1
   1147 				comment_end: int
   1148 
   1149 				comment_loop: for i := int(start_offset); i >= 0; {
   1150 					c := utf8.rune_at(src, i)
   1151 					defer i -= utf8.rune_size(c)
   1152 					switch find_state {
   1153 					case .Looking_For_Start:
   1154 						if c == '#' {
   1155 							comment_end = i
   1156 							find_state = .Looking_For_Comment
   1157 							break
   1158 						}
   1159 
   1160 						if c == '\n' {
   1161 							break comment_loop
   1162 						}
   1163 					case .Looking_For_Comment:
   1164 						if unicode.is_white_space(c) {
   1165 							break
   1166 						}
   1167 
   1168 						if c == '/' && i > 1 && src[i - 1] == '*' {
   1169 							find_state = .Inside_Block_Comment
   1170 							break
   1171 						}
   1172 
   1173 						// TODO: Special case when line only is `//`
   1174 
   1175 						find_state = .Looking_For_Single_Line_Start
   1176 					case .Looking_For_Single_Line_Start:
   1177 						if c == '\n' {
   1178 							break comment_loop
   1179 						}
   1180 
   1181 						if c == '/' && i < len(src) - 1 && src[i + 1] == '/' {
   1182 							find_state = .Verifying_Single_Line
   1183 							break
   1184 						}
   1185 
   1186 					case .Verifying_Single_Line:
   1187 						if c == '\n' {
   1188 							comment_start = i
   1189 							find_state = .Looking_For_Comment
   1190 							break
   1191 						}
   1192 
   1193 						if !unicode.is_white_space(c) {
   1194 							break comment_loop
   1195 						}
   1196 					case .Inside_Block_Comment:
   1197 						if c == '/' && i < len(src) - 1 && src[i + 1] == '*' {
   1198 							comment_start = i
   1199 							find_state = .Looking_For_Comment
   1200 							break
   1201 						}
   1202 					}
   1203 				}
   1204 
   1205 				if comment_start != -1 && comment_end > comment_start {
   1206 					comment = strings.trim_space(src[comment_start:comment_end])
   1207 				}
   1208 			}
   1209 		}
   1210 
   1211 		tokens: [^]clang.Token
   1212 		token_count: u32
   1213 		clang.tokenize(translation_unit, source_range, &tokens, &token_count)
   1214 
   1215 		return {
   1216 			original_name = cursor_spelling(cursor),
   1217 			tokens = tokens[:token_count],
   1218 			has_been_evaluated = false,
   1219 			is_function = bool(clang.Cursor_isMacroFunctionLike(cursor)),
   1220 			comment = comment,
   1221 			side_comment = side_comment,
   1222 			whitespace_before_side_comment = side_comment_align_whitespace,
   1223 			whitespace_after_name = whitespace_after_name,
   1224 		}
   1225 	}
   1226 
   1227 	root_cursor_visitor_proc: clang.Cursor_Visitor : proc "c" (
   1228 		cursor, parent: clang.Cursor,
   1229 		state: clang.Client_Data,
   1230 	) -> clang.Child_Visit_Result {
   1231 		context = runtime.default_context()
   1232 		state := (^Gen_State)(state)
   1233 
   1234 		file: clang.File
   1235 		_ = cursor_location(cursor, &file)
   1236 		if !bool(clang.File_isEqual(file, state.file)) {
   1237 			return .Continue // This cursor is not in the file we are interested in.
   1238 		}
   1239 
   1240 		kind := clang.getCursorKind(cursor)
   1241 		#partial switch kind {
   1242 		case .MacroDefinition:
   1243 			if bool(clang.Cursor_isMacroBuiltin(cursor)) {
   1244 				return .Continue
   1245 			}
   1246 
   1247 			append(&state.decls, Declaration {
   1248 				cursor = cursor,
   1249 				original_idx = len(state.decls),
   1250 				variant = parse_macro_decl(state, cursor),
   1251 			})
   1252 			return .Continue
   1253 		case .FunctionDecl:
   1254 			if clang.Cursor_isFunctionInlined(cursor) != 0 {
   1255 				return .Continue
   1256 			}
   1257 
   1258 			append(&state.decls, Declaration {
   1259 				cursor = cursor,
   1260 				original_idx = len(state.decls),
   1261 				variant = parse_function_decl(state, cursor),
   1262 			})
   1263 			return .Continue
   1264 		}
   1265 
   1266 		def: Declaration_Variant
   1267 		#partial switch kind {
   1268 		case .StructDecl, .UnionDecl:
   1269 			def = parse_record_decl(state, cursor)
   1270 		case .TypedefDecl:
   1271 			def = parse_typedef_decl(state, cursor)
   1272 		case .EnumDecl:
   1273 			def = parse_enum_decl(state, cursor)
   1274 		}
   1275 
   1276 		append(&state.decls, Declaration {
   1277 			cursor = cursor,
   1278 			original_idx = len(state.decls),
   1279 			variant = def,
   1280 		})
   1281 
   1282 		return .Continue
   1283 	}
   1284 
   1285 	root_cursor := clang.getTranslationUnitCursor(unit)
   1286 
   1287 	input_filename := filepath.base(input)
   1288 	output_stem := filepath.stem(input_filename)
   1289 	output_filename := fmt.tprintf("%v/%v.odin", s.output_folder, output_stem)
   1290 
   1291 	if c.debug_dump_ast {
   1292 		dump_ast(root_cursor, s.file, fmt.tprintf("%v/%v.yml", s.output_folder, output_stem))
   1293 	}
   1294 	clang.visitChildren(root_cursor, root_cursor_visitor_proc, &s)
   1295 
   1296 	slice.sort_by(s.decls[:], proc(i, j: Declaration) -> bool {
   1297 		// This should work but I get a linker error. Is the version of libclang from VS dev tools outdated?
   1298 		// return bool(clang.isBeforeInTranslationUnit(clang.getCursorLocation(i.cursor), clang.getCursorLocation(j.cursor)))
   1299 
   1300 		// This should be fine for now.
   1301 		return cursor_location(i.cursor) < cursor_location(j.cursor)
   1302 	})
   1303 
   1304 	//
   1305 	// Use the stuff in `s` and `s.decl` to write out the bindings.
   1306 	//
   1307 
   1308 	f, f_err := os.open(output_filename, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0o644)
   1309 
   1310 	fmt.ensuref(f_err == nil, "Failed opening %v", output_filename)
   1311 	defer os.close(f)
   1312 
   1313 	// Extract any big comment at top of file (clang doesn't see these)
   1314 	{
   1315 		source := strings.trim_space(s.source)
   1316 		in_block := false
   1317 		top_comment_loop: for ll in strings.split_lines_iterator(&source) {
   1318 			l := strings.trim_space(ll)
   1319 
   1320 			if in_block {
   1321 				fpln(f, l)
   1322 				if strings.contains(l, "*/") {
   1323 					in_block = false
   1324 				}
   1325 			} else {
   1326 				if len(l) < 2 {
   1327 					continue
   1328 				}
   1329 
   1330 				switch l[:2] {
   1331 				case "//":
   1332 					fpln(f, l)
   1333 				case "/*":
   1334 					in_block = !strings.contains(l, "*/")
   1335 					fpln(f, l)
   1336 				case:
   1337 					break top_comment_loop
   1338 				}
   1339 			}
   1340 		}
   1341 	}
   1342 
   1343 	fpf(f, "package %v\n\n", s.package_name)
   1344 
   1345 	if s.needs_import_c {
   1346 		fpln(f, `import "core:c"`)
   1347 	}
   1348 
   1349 	if s.needs_import_libc {
   1350 		fpln(f, `import "core:c/libc"`)
   1351 	}
   1352 
   1353 	if s.needs_import_posix {
   1354 		fpln(f, `import "core:sys/posix"`)
   1355 	}
   1356 
   1357 	fp(f, "\n")
   1358 
   1359 	if s.needs_import_c {
   1360 		fpln(f, "_ :: c")
   1361 	}
   1362 	if s.needs_import_libc {
   1363 		fpln(f, "_ :: libc")
   1364 	}
   1365 	if s.needs_import_posix {
   1366 		fpln(f, "_ :: posix")
   1367 	}
   1368 
   1369 	fp(f, "\n")
   1370 
   1371 	if s.imports_file != "" {
   1372 		top_code, top_code_ok := os.read_entire_file(s.imports_file)
   1373 		fmt.ensuref(top_code_ok, "Failed to load %v", s.imports_file)
   1374 		fp(f, string(top_code))
   1375 	} else if s.import_lib != "" {
   1376 		fpf(f, `foreign import lib "%v"`, s.import_lib)
   1377 	}
   1378 
   1379 	fp(f, "\n\n")
   1380 
   1381 	output_comment :: proc(f: os.Handle, c: string, indent := "") {
   1382 		ci := c
   1383 		for l in strings.split_lines_iterator(&ci) {
   1384 			fp(f, indent)
   1385 			fpln(f, strings.trim_space(l))
   1386 		}
   1387 	}
   1388 
   1389 	//
   1390 	// Figure out all type names
   1391 	//
   1392 
   1393 	for &decl, i in s.decls {
   1394 		du := &decl.variant
   1395 		switch &d in du {
   1396 		case Struct:
   1397 			if d.is_anon {
   1398 				s.symbol_indices[d.original_name] = i
   1399 				continue // Skip anonymous structs.
   1400 			}
   1401 
   1402 			name := d.original_name
   1403 			if typedef, has_typedef := s.typedefs[d.id]; has_typedef {
   1404 				d.original_name = typedef
   1405 				name = typedef
   1406 			}
   1407 			name = translate_name(&s, name)
   1408 
   1409 			d.name = vet_name(name)
   1410 			add_to_set(&s.created_types, d.name)
   1411 			add_to_set(&s.created_symbols, name)
   1412 		case Function:
   1413 			name := d.original_name
   1414 
   1415 			if replacement, has_replacement := s.rename[name]; has_replacement {
   1416 				d.link_name = d.original_name
   1417 				name = replacement
   1418 			} else {
   1419 				name = trim_prefix(name, s.remove_function_prefix)
   1420 			}
   1421 
   1422 			d.name = vet_name(name)
   1423 		case Enum:
   1424 			name := d.original_name
   1425 
   1426 			if typedef, has_typedef := s.typedefs[d.id]; has_typedef {
   1427 				d.original_name = typedef
   1428 				name = typedef
   1429 			}
   1430 			name = translate_name(&s, name)
   1431 			
   1432 			d.name = vet_name(name)
   1433 			add_to_set(&s.created_symbols, d.name)
   1434 			add_to_set(&s.created_types, d.name)
   1435 		case Typedef:
   1436 			name := d.original_name
   1437 
   1438 			if name in c_type_mapping {
   1439 				continue
   1440 			}
   1441 
   1442 			name = translate_name(&s, name)
   1443 			d.name = vet_name(name)
   1444 			add_to_set(&s.created_types, d.name)
   1445 		case Macro:
   1446 			name := d.original_name
   1447 			s.macro_defines[name] = i
   1448 
   1449 			if replacement, has_replacement := s.rename[name]; has_replacement {
   1450 				name = replacement
   1451 			} else {
   1452 				name = trim_prefix(name, s.remove_macro_prefix)
   1453 			}
   1454 
   1455 			d.name = vet_name(name)
   1456 		}
   1457 	}
   1458 
   1459 	for _, b in s.bit_setify {
   1460 		add_to_set(&s.created_types, b)
   1461 	}
   1462 
   1463 	for &decl, decl_idx in s.decls {
   1464 		output_struct :: proc(s: ^Gen_State, d: Struct, indent: int, n: string) -> string {
   1465 			w := strings.builder_make()
   1466 			ws :: strings.write_string
   1467 			ws(&w, "struct ")
   1468 
   1469 			if d.is_union {
   1470 				ws(&w, "#raw_union ")
   1471 			}
   1472 
   1473 			if len(d.fields) == 0 {
   1474 				ws(&w, "{}")
   1475 				return strings.to_string(w)
   1476 			}
   1477 
   1478 			ws(&w, "{\n")
   1479 
   1480 			longest_field_name_with_side_comment: int
   1481 
   1482 			for &field in d.fields {
   1483 				if bool(clang.Cursor_isAnonymous(clang.getTypeDeclaration(field.type))) {
   1484 					continue
   1485 				}
   1486 
   1487 				field_len: int
   1488 				for fn, nidx in field.names {
   1489 					if nidx != 0 {
   1490 						field_len += 2 // for comma and space
   1491 					}
   1492 
   1493 					field_len += len(vet_name(fn))
   1494 				}
   1495 				if (field.comment == "" || !field.comment_before) && field_len > longest_field_name_with_side_comment {
   1496 					longest_field_name_with_side_comment = field_len
   1497 				}
   1498 			}
   1499 
   1500 			Formatted_Field :: struct {
   1501 				field:          string,
   1502 				comment:        string,
   1503 				comment_before: bool,
   1504 			}
   1505 
   1506 			fields: [dynamic]Formatted_Field
   1507 
   1508 			for &field in d.fields {
   1509 				b := strings.builder_make()
   1510 
   1511 				override_key: string
   1512 
   1513 				if field.anon_using {
   1514 					strings.write_string(&b, "using _: ")
   1515 				} else {
   1516 					for fn, nidx in field.names {
   1517 						if nidx != 0 {
   1518 							strings.write_string(&b, ", ")
   1519 						}
   1520 						strings.write_string(&b, vet_name(fn))
   1521 					}
   1522 
   1523 					names_len := strings.builder_len(b)
   1524 					override_key = fmt.tprintf("%s.%s", d.original_name, strings.to_string(b))
   1525 					strings.write_string(&b, ": ")
   1526 
   1527 					if !field.comment_before {
   1528 						// Padding between name and =
   1529 						for _ in 0..<longest_field_name_with_side_comment-names_len {
   1530 							strings.write_rune(&b, ' ')
   1531 						}
   1532 					}
   1533 				}
   1534 
   1535 				field_type: string
   1536 				
   1537 				if field_type_override, has_field_type_override := s.struct_field_overrides[override_key]; override_key != "" && has_field_type_override {
   1538 					if field_type_override == "[^]" {
   1539 						field_type, _ = parse_type(s, field.type, {.Pointer_To_Array})
   1540 					} else {
   1541 						field_type = field_type_override
   1542 					}
   1543 				} else {
   1544 					field_type, _ = parse_type(s, field.type, nil)
   1545 				}
   1546 
   1547 				comment := field.comment
   1548 				comment_before := field.comment_before
   1549 
   1550 				if bool(clang.Cursor_isAnonymous(clang.getTypeDeclaration(field.type))) {
   1551 					decl_index, exists := s.symbol_indices[cursor_spelling(clang.getTypeDeclaration(field.type))]
   1552 					if exists {
   1553 						anon_struct := s.decls[decl_index].variant.(Struct)
   1554 						if anon_struct.comment != "" {
   1555 							comment = anon_struct.comment
   1556 							comment_before = true
   1557 						}
   1558 
   1559 						field_type = output_struct(s, anon_struct, indent + 1, n)
   1560 					}
   1561 				}
   1562 
   1563 				strings.write_string(&b, field_type)
   1564 
   1565 				append(&fields, Formatted_Field {
   1566 					field = strings.to_string(b),
   1567 					comment = comment,
   1568 					comment_before = comment_before,
   1569 				})
   1570 			}
   1571 
   1572 			longest_field_with_side_comment: int
   1573 
   1574 			for &field in fields {
   1575 				if field.comment != "" && !field.comment_before {
   1576 					longest_field_with_side_comment = max(len(field.field), longest_field_with_side_comment)
   1577 				}
   1578 			}
   1579 
   1580 			for &field, field_idx in fields {
   1581 				has_comment := field.comment != ""
   1582 				comment_before := field.comment_before
   1583 
   1584 				if has_comment && comment_before {
   1585 					if field_idx != 0 {
   1586 						ws(&w, "\n")
   1587 					}
   1588 
   1589 					ci := field.comment
   1590 					for l in strings.split_lines_iterator(&ci) {
   1591 						for _ in 0..<indent+1 {
   1592 							ws(&w, "\t")
   1593 						}
   1594 						ws(&w, strings.trim_space(l))
   1595 						ws(&w, "\n")
   1596 					}
   1597 				}
   1598 
   1599 				for _ in 0..<indent+1 {
   1600 					ws(&w, "\t")
   1601 				}
   1602 				ws(&w, field.field)
   1603 				ws(&w, ",")
   1604 
   1605 				if has_comment && !comment_before {
   1606 					// Padding in front of comment
   1607 					for _ in 0..<(longest_field_with_side_comment - len(field.field)) {
   1608 						ws(&w, " ")
   1609 					}
   1610 
   1611 					ws(&w, " ")
   1612 					ws(&w, field.comment)
   1613 				}
   1614 
   1615 				ws(&w, "\n")
   1616 			}
   1617 
   1618 			for _ in 0..<indent {
   1619 				ws(&w, "\t")
   1620 			}
   1621 			ws(&w, "}")
   1622 			return strings.to_string(w)
   1623 		}
   1624 
   1625 		du := &decl.variant
   1626 		switch &d in du {
   1627 		case Struct:
   1628 			if d.is_anon {
   1629 				continue // Skip anonymous structs.
   1630 			}
   1631 
   1632 			n := d.name
   1633 
   1634 			if d.is_forward_declare {
   1635 				if d.original_name in s.opaque_type_lookup && d.id not_in s.typedefs {
   1636 					output_comment(f, d.comment)
   1637 					fpf(f, "%v :: struct {{}}\n\n", n)
   1638 				}
   1639 
   1640 				break
   1641 			}
   1642 
   1643 			output_comment(f, d.comment)
   1644 
   1645 			if inject, has_injection := s.inject_before[d.original_name]; has_injection {
   1646 				fpf(f, "%v\n\n", inject)
   1647 			}
   1648 
   1649 			fp(f, n)
   1650 			fp(f, " :: ")
   1651 
   1652 			if override, override_ok := s.type_overrides[d.original_name]; override_ok {
   1653 				fp(f, override)
   1654 				fp(f, "\n\n")
   1655 				break
   1656 			}
   1657 
   1658 			fp(f, output_struct(&s, d, 0, n))
   1659 			fp(f, "\n\n")
   1660 		case Enum:
   1661 			output_comment(f, d.comment)
   1662 
   1663 			name := d.name
   1664 
   1665 			// It has no name, turn it into a bunch of constants
   1666 			if name == "" {
   1667 				for &m in d.members {
   1668 					mn := m.name
   1669 
   1670 					if strings.has_prefix(strings.to_lower(mn), strings.to_lower(s.remove_type_prefix)) {
   1671 						mn = mn[len(s.remove_type_prefix):]
   1672 
   1673 						if strings.has_prefix(mn, "_") {
   1674 							mn = mn[1:]
   1675 						}
   1676 					}
   1677 
   1678 					fpf(f, "%v :: %v\n\n", mn, m.value)
   1679 				}
   1680 
   1681 				break
   1682 			}
   1683 
   1684 			fp(f, name)
   1685 			{
   1686 				str, _ := parse_type(&s, d.backing_type, nil)
   1687 				fpf(f, " :: enum %v {{\n", str)
   1688 			}
   1689 
   1690 			bit_set_name, bit_setify := s.bit_setify[d.original_name]
   1691 			make_constant: map[string]int
   1692 
   1693 			if bit_setify {
   1694 				for &m in d.members {
   1695 					if bits.count_ones(m.value) != 1 { // Not a power of two, so not part of a bit_set.
   1696 						make_constant[m.name] = m.value
   1697 						continue
   1698 					}
   1699 					m.value = (int)(bits.log2((uint)(m.value)))
   1700 				}
   1701 			}
   1702 
   1703 			overlap_length := 0
   1704 			longest_name := 0
   1705 
   1706 			all_has_default_value := true
   1707 			counter := 0
   1708 			for &m in d.members {
   1709 				if _, skip := make_constant[m.name]; skip {
   1710 					continue
   1711 				}
   1712 
   1713 				if m.value != counter {
   1714 					all_has_default_value = false
   1715 					break
   1716 				}
   1717 				counter += 1
   1718 			}
   1719 
   1720 			if len(d.members) > 1 {
   1721 				overlap_length_source := d.members[0].name
   1722 				overlap_length = len(overlap_length_source)
   1723 				longest_name = overlap_length
   1724 
   1725 				for idx in 1..<len(d.members) {
   1726 					if _, skip := make_constant[d.members[idx].name]; skip {
   1727 						continue
   1728 					}
   1729 
   1730 					mn := d.members[idx].name
   1731 					length := strings.prefix_length(mn, overlap_length_source)
   1732 
   1733 					if length < overlap_length {
   1734 						overlap_length = length
   1735 						overlap_length_source = mn
   1736 					}
   1737 
   1738 					longest_name = max(len(mn), longest_name)
   1739 				}
   1740 			}
   1741 
   1742 			Formatted_Member :: struct {
   1743 				name:           string,
   1744 				member:         string,
   1745 				enum_member:    ^Enum_Member,
   1746 			}
   1747 
   1748 			members: [dynamic]Formatted_Member
   1749 
   1750 			for &m in d.members {
   1751 				if _, skip := make_constant[m.name]; skip {
   1752 					continue
   1753 				}
   1754 
   1755 				b := strings.builder_make()
   1756 
   1757 				name_without_overlap := m.name[overlap_length:]
   1758 
   1759 				// I added this to fix something but I dont think we actually need it anymore.
   1760 				// If you see any enum members that start with an underscore uncomment this.
   1761 				// Remove any leading underscores.
   1762 				// for ; name_without_overlap[0] == '_'; name_without_overlap = name_without_overlap[1:] {}
   1763 
   1764 				// First letter is number... Can't have that!
   1765 				if len(name_without_overlap) > 0 && unicode.is_number(utf8.rune_at(name_without_overlap, 0)) {
   1766 					name_without_overlap = fmt.tprintf("_%v", name_without_overlap)
   1767 				}
   1768 
   1769 				strings.write_string(&b, name_without_overlap)
   1770 
   1771 				suffix_pad := longest_name - len(name_without_overlap) - overlap_length
   1772 
   1773 				if !all_has_default_value {
   1774 					if !m.comment_before {
   1775 						for _ in 0..<suffix_pad {
   1776 							// Padding between name and `=`
   1777 							strings.write_rune(&b, ' ')
   1778 						}
   1779 					}
   1780 
   1781 					strings.write_string(&b, fmt.tprintf(" = %v", m.value))
   1782 				}
   1783 
   1784 				append(&members, Formatted_Member {
   1785 					name = name_without_overlap,
   1786 					member = strings.to_string(b),
   1787 					enum_member = &m,
   1788 				})
   1789 			}
   1790 
   1791 			longest_member_name_with_side_comment: int
   1792 
   1793 			for &m in members {
   1794 				if m.enum_member.comment != "" && !m.enum_member.comment_before && len(m.member) > longest_member_name_with_side_comment {
   1795 					longest_member_name_with_side_comment = len(m.member)
   1796 				}
   1797 			}
   1798 
   1799 			for &m, m_idx in members {
   1800 				has_comment := m.enum_member.comment != ""
   1801 				comment_before := m.enum_member.comment_before
   1802 
   1803 				if has_comment && comment_before {
   1804 					if m_idx != 0 {
   1805 						fp(f, "\n")
   1806 					}
   1807 					output_comment(f, m.enum_member.comment, "\t")
   1808 				}
   1809 
   1810 				fp(f, "\t")
   1811 				fp(f, m.member)
   1812 				fp(f, ",")
   1813 
   1814 				if has_comment && !comment_before {
   1815 					for _ in 0..<(longest_member_name_with_side_comment - len(m.member)) {
   1816 						// Padding in front of comment
   1817 						fp(f, " ")
   1818 					}
   1819 
   1820 					fpf(f, " %v", m.enum_member.comment)
   1821 				}
   1822 
   1823 				fp(f, '\n')
   1824 			}
   1825 
   1826 			fp(f, "}\n\n")
   1827 
   1828 			if bit_setify {
   1829 				str, _ := parse_type(&s, d.backing_type, nil)
   1830 				fpf(f, "%v :: distinct bit_set[%v; %v]\n\n", bit_set_name, name, str)
   1831 
   1832 				// In case there is a typedef for this in the code.
   1833 				add_to_set(&s.created_symbols, bit_set_name)
   1834 
   1835 				// There was a member with a compound value, so we need to
   1836 				// decompose it into a constant bit set
   1837 				for constant_name, constant_val in make_constant {
   1838 					all_constant := strings.to_screaming_snake_case(trim_prefix(strings.to_lower(constant_name), strings.to_lower(s.remove_type_prefix)))
   1839 
   1840 					if constant_val == 0 {
   1841 						// If the value is 0, we don't need to output it.
   1842 						// This is because the zero value of a bit set is an empty set.
   1843 						continue
   1844 					}
   1845 
   1846 					fpf(f, "%v :: %v {{ ", all_constant, bit_set_name)
   1847 
   1848 					for &m, i in members {
   1849 						if (1 << uint(m.enum_member.value)) & constant_val != 0 {
   1850 							fpf(f, ".%v", m.name)
   1851 
   1852 							if i != len(members) - 1 {
   1853 								fp(f, ", ")
   1854 							}
   1855 						}
   1856 					}
   1857 
   1858 					fp(f, " }\n\n")
   1859 				}
   1860 			}
   1861 
   1862 		case Function:
   1863 			// handled later. This makes all procs end up at bottom, after types.
   1864 		case Typedef:
   1865 			n := d.name
   1866 
   1867 			if n == "" {
   1868 				// The name was a C type, so we don't need to output it.
   1869 				continue
   1870 			}
   1871 
   1872 			if d.original_name in s.opaque_type_lookup {
   1873 				if d.pre_comment != "" {
   1874 					output_comment(f, d.pre_comment)
   1875 				}
   1876 				fpf(f, "%v :: struct {{}}", n)
   1877 
   1878 				if d.side_comment != "" {
   1879 					fp(f, ' ')
   1880 					fp(f, d.side_comment)
   1881 				}
   1882 
   1883 				fp(f, "\n\n")
   1884 				continue
   1885 			}
   1886 
   1887 			type_string := type_spelling(d.type)
   1888 			if n in s.created_symbols || strings.has_prefix(type_string, "0x") {
   1889 				continue
   1890 			}
   1891 
   1892 			parsed_type, _ := parse_type(&s, d.type, nil)
   1893 			if parsed_type == d.name {
   1894 				continue
   1895 			}
   1896 
   1897 			if d.pre_comment != "" {
   1898 				output_comment(f, d.pre_comment)
   1899 			}
   1900 
   1901 			fp(f, n)
   1902 
   1903 			fp(f, " :: ")
   1904 
   1905 			if override, override_ok := s.type_overrides[d.original_name]; override_ok {
   1906 				fp(f, override)
   1907 
   1908 				if d.side_comment != "" {
   1909 					output_comment(f, d.side_comment)
   1910 				}
   1911 
   1912 				fp(f, "\n\n")
   1913 				continue
   1914 			}
   1915 
   1916 			if strings.has_prefix(type_string, "struct ") {
   1917 				// This is a weird case -- I used this for opaque types in the
   1918 				// beginning, but opaque types are now handled by
   1919 				// `s.opaque_type_lookup`, so perhaps this isn't needed anymore?
   1920 				fp(f, "struct {}")
   1921 			} else if strings.contains(type_string, "(") && strings.contains(type_string, ")") {
   1922 				// function pointer typedef
   1923 				fp(f, parsed_type)
   1924 				add_to_set(&s.type_is_proc, n)
   1925 			} else {
   1926 				fpf(f, "%v", parsed_type)
   1927 			}
   1928 
   1929 			if d.side_comment != "" {
   1930 				fp(f, ' ')
   1931 				fp(f, d.side_comment)
   1932 			}
   1933 
   1934 			fp(f, "\n\n")
   1935 		case Macro:
   1936 			// I'm not particularly proud of this implementation.
   1937 			// It could probably be massively simplified and improved.
   1938 
   1939 			parse_literal :: proc(token_str: string) -> string {
   1940 				switch token_str[0] {
   1941 				case '0'..='9':
   1942 					token_str := token_str
   1943 					if len(token_str) == 1 {
   1944 						return token_str
   1945 					}
   1946 
   1947 					hex := false
   1948 					if token_str[1] == 'x' {
   1949 						hex = true
   1950 					} else if token_str[1] == 'X' {
   1951 						hex = true
   1952 						// Odin requires hex x to be lowercase.
   1953 						tmp := transmute([]u8)(token_str)
   1954 						tmp[1] = 'x'
   1955 					}
   1956 
   1957 					index := len(token_str) - 1
   1958 					LOOP: for ; index > 0; index -= 1 {
   1959 						switch token_str[index] {
   1960 						case 'L', 'l', 'U', 'u':
   1961 							// These are suffixes for long and unsigned literals.
   1962 							continue LOOP
   1963 						case 'F', 'f':
   1964 							if hex {
   1965 								break LOOP
   1966 							}
   1967 							// Floating point literals can have 'F' or 'f' suffixes.
   1968 							continue LOOP
   1969 						case:
   1970 							// Not a suffix char.
   1971 							break LOOP
   1972 						}
   1973 					}
   1974 					return token_str[:index + 1]
   1975 				case '"':
   1976 					// String literal
   1977 					// We'll need to make some considerations here when we want to handle '#' operations.
   1978 					return token_str
   1979 				}
   1980 				return token_str
   1981 			}
   1982 
   1983 			parse_identifier :: proc(state: ^Gen_State, cursor: clang.Cursor, macro: ^Macro, index: int) -> (string, int) {
   1984 				// Could be a type or macro name. Could also be the name of a function or variable.
   1985 				tu := clang.Cursor_getTranslationUnit(cursor)
   1986 				token := macro.tokens[index]
   1987 				token_str := token_string(tu, token)
   1988 
   1989 				if token_str == "true" || token_str == "false" {
   1990 					return token_str, 0
   1991 				}
   1992 
   1993 				if token_str in state.created_types {
   1994 					return token_str, 0
   1995 			    }
   1996 
   1997 				if decl_index, exists := state.macro_defines[token_str]; exists {
   1998 					val, offset := expand_inner_macro(state, cursor, macro, &state.decls[decl_index], index)
   1999 					if !state.decls[decl_index].variant.(Macro).should_not_output {
   2000 						val = state.decls[decl_index].variant.(Macro).name
   2001 					}
   2002 					return val, offset
   2003 				}
   2004 
   2005 				return translate_type_string(state, token_str), 0
   2006 			}
   2007 
   2008 			parse_format_string :: proc(str: string, args: []string) -> string {
   2009 				// Replaces ${0}, ${1}, etc. with the corresponding argument.
   2010 				builder := strings.builder_make()
   2011 				for i := 0; i < len(str); i += 1 {
   2012 					if i + 1 < len(str) && str[i] == '$' && str[i + 1] == '{' {
   2013 						i += 2
   2014 						for j := i; j < len(str); j += 1 {
   2015 							if str[j] == '}' {
   2016 								if num, ok := strconv.parse_int(str[i:j], 10); ok {
   2017 									strings.write_string(&builder, args[num])
   2018 									i = j
   2019 									break
   2020 								}
   2021 							}
   2022 						}
   2023 					} else {
   2024 						strings.write_byte(&builder, str[i])
   2025 					}
   2026 				}
   2027 				return strings.to_string(builder)
   2028 			}
   2029 
   2030 			get_fn_macro_params :: proc(state: ^Gen_State, cursor: clang.Cursor, macro: ^Macro, index: int) -> ([]string, int) {
   2031 				if index >= len(macro.tokens) {
   2032 					return nil, 0 // No parameters.
   2033 				}
   2034 				
   2035 				tu := clang.Cursor_getTranslationUnit(cursor)
   2036 
   2037 				{
   2038 					token_str := token_string(tu, macro.tokens[index])
   2039 					if token_str[0] != '(' {
   2040 						return nil, 0 // No parameters.
   2041 					}
   2042 				}
   2043 
   2044 				params: [dynamic]string
   2045 				builder := strings.builder_make()
   2046 				for loop_index := index; loop_index < len(macro.tokens); loop_index += 1 {
   2047 					token := macro.tokens[loop_index]
   2048 
   2049 					paren_count := 1
   2050 					token_str := token_string(tu, token)
   2051 					#partial switch clang.getTokenKind(token) {
   2052 					case .Punctuation:
   2053 						switch token_str[0] {
   2054 						case '(':
   2055 							paren_count += 1
   2056 						case ')':
   2057 							paren_count -= 1
   2058 							if paren_count == 0 {
   2059 								append(&params, strings.to_string(builder))
   2060 								return params[:], loop_index - index + 1
   2061 							}
   2062 						case ',':
   2063 							if paren_count == 1 {
   2064 								append(&params, strings.to_string(builder))
   2065 								builder = strings.builder_make() // Reset the builder for the next parameter.
   2066 							}
   2067 						}
   2068 					case .Keyword:
   2069 						tokens_str := token_str
   2070 						tokens_count := 0
   2071 						for t in macro.tokens[index + 1:] {
   2072 							if clang.getTokenKind(t) == .Keyword {
   2073 								tokens_str = fmt.tprint(tokens_str, token_string(tu, t))
   2074 								tokens_count += 1
   2075 							} else {
   2076 								break
   2077 							}
   2078 						}
   2079 
   2080 						if keyword_string := translate_type_string(state, tokens_str); keyword_string != "" {
   2081 							strings.write_string(&builder, keyword_string)
   2082 							loop_index += tokens_count
   2083 						} else {
   2084 							if keyword_string = translate_type_string(state, token_str); keyword_string != "" {
   2085 								strings.write_string(&builder, keyword_string)
   2086 							}
   2087 						}
   2088 					case .Identifier:
   2089 						val, offset := parse_identifier(state, cursor, macro, loop_index)
   2090 						loop_index += offset
   2091 						if val == "" {
   2092 							// macro.should_not_output = true
   2093 							val = token_str // Fallback to the original token string.
   2094 						}
   2095 
   2096 						if strings.contains_rune(val, ',') {
   2097 							encapsulation := 0
   2098 							for r in val {
   2099 								switch r {
   2100 								case '(':
   2101 									encapsulation += 1
   2102 								case ')':
   2103 									encapsulation -= 1
   2104 								case ',':
   2105 									if encapsulation == 0 {
   2106 										// We found a comma at the top level, so we need to split this parameter.
   2107 										append(&params, strings.to_string(builder))
   2108 										builder = strings.builder_make() // Reset the builder for the next parameter.
   2109 										continue
   2110 									}
   2111 								case:
   2112 									strings.write_rune(&builder, r)
   2113 								}
   2114 							}
   2115 						} else {
   2116 							strings.write_string(&builder, val)
   2117 						}
   2118 					case .Literal:
   2119 						strings.write_string(&builder, parse_literal(token_str))
   2120 					}
   2121 				}
   2122 				return nil, 0 // We didn't find the closing parenthesis.
   2123 			}
   2124 
   2125 			expand_inner_macro :: proc(state: ^Gen_State, cursor: clang.Cursor, macro: ^Macro, decl: ^Declaration, index: int) -> (val: string, offset: int) {
   2126 				decl_macro := &decl.variant.(Macro)
   2127 				if !decl_macro.has_been_evaluated {
   2128 					evaluate_macro(state, decl.cursor, decl_macro)
   2129 				}
   2130 
   2131 				if decl_macro.is_function {
   2132 					params: []string
   2133 					params, offset = get_fn_macro_params(state, cursor, macro, index + 1)
   2134 					if params == nil {
   2135 						// We couldn't find the parameters.
   2136 						macro.should_not_output = true
   2137 						return "", 0
   2138 					}
   2139 
   2140 					parsed_fn_string := parse_format_string(decl_macro.val, params)
   2141 					if parsed_fn_string == "" {
   2142 						// Couldn't parse the function macro.
   2143 						// Parameters were probably wrong.
   2144 						macro.should_not_output = true
   2145 						return "", 0
   2146 					}
   2147 
   2148 					val = parsed_fn_string
   2149 				} else {
   2150 					val = decl_macro.val
   2151 				}
   2152 				return
   2153 			}
   2154 
   2155 			evaluate_fn_macro :: proc(state: ^Gen_State, cursor: clang.Cursor, macro: ^Macro) {
   2156 				macro.should_not_output = true
   2157 				params, offset := get_fn_macro_params(state, cursor, macro, 1)
   2158 				if params == nil {
   2159 					// We couldn't find the parameters.
   2160 					return
   2161 				}
   2162 
   2163 				paramsMap: map[string]int
   2164 				for p, i in params {
   2165 					paramsMap[p] = i
   2166 				}
   2167 				
   2168 				tu := clang.Cursor_getTranslationUnit(cursor)
   2169 				builder := strings.builder_make()
   2170 				for index := offset + 1; index < len(macro.tokens); index += 1 {
   2171 					token := macro.tokens[index]
   2172 
   2173 					token_str := token_string(tu, token)
   2174 
   2175 					if replace_val, has_replace := paramsMap[token_str]; has_replace {
   2176 						// If the token is a parameter, replace it with the corresponding value.
   2177 						buf: [10]byte // We can have upto 10 digits
   2178 						strings.write_string(&builder, "${")
   2179 						strings.write_string(&builder, strconv.write_int(buf[:], i64(replace_val), 10))
   2180 						strings.write_rune(&builder, '}')
   2181 						continue
   2182 					}
   2183 
   2184 					#partial switch clang.getTokenKind(token) {
   2185 					case .Punctuation:
   2186 						switch token_str[0] {
   2187 						case '#':
   2188 							macro.should_not_output = true
   2189 							strings.write_string(&builder, token_str)
   2190 						case:
   2191 							strings.write_string(&builder, token_str)
   2192 						}
   2193 					case .Keyword:
   2194 						tokens_str := token_str
   2195 						tokens_count := 0
   2196 						for t in macro.tokens[index + 1:] {
   2197 							if clang.getTokenKind(t) == .Keyword {
   2198 								tokens_str = fmt.tprint(tokens_str, token_string(tu, t))
   2199 								tokens_count += 1
   2200 							} else {
   2201 								break
   2202 							}
   2203 						}
   2204 
   2205 						if keyword_string := translate_type_string(state, tokens_str); keyword_string != "" {
   2206 							strings.write_string(&builder, keyword_string)
   2207 							index += tokens_count
   2208 						} else {
   2209 							if keyword_string = translate_type_string(state, token_str); keyword_string != "" {
   2210 								strings.write_string(&builder, keyword_string)
   2211 							}
   2212 						}
   2213 					case .Identifier:
   2214 						val, offset2 := parse_identifier(state, cursor, macro, index)
   2215 						index += offset2
   2216 						if val == "" {
   2217 							// macro.should_not_output = true
   2218 							val = token_str // Fallback to the original token string.
   2219 						}
   2220 						strings.write_string(&builder, val)
   2221 					case .Literal:
   2222 						val := parse_literal(token_str)
   2223 						if val == "" {
   2224 							macro.should_not_output = true
   2225 							val = token_str // Fallback to the original token string.
   2226 						}
   2227 						strings.write_string(&builder, val)
   2228 					}
   2229 				}
   2230 				macro.val = strings.to_string(builder)
   2231 			}
   2232 
   2233 			evaluate_nonfn_macro :: proc(state: ^Gen_State, cursor: clang.Cursor, macro: ^Macro) {
   2234 				builder := strings.builder_make()
   2235 				curly_parens := 0
   2236 				for index := 1; index < len(macro.tokens); index += 1 {
   2237 					token := macro.tokens[index]
   2238 					tu := clang.Cursor_getTranslationUnit(cursor)
   2239 					token_str := token_string(tu, token)
   2240 
   2241 					#partial switch clang.getTokenKind(token) {
   2242 					case .Identifier:
   2243 						val, offset := parse_identifier(state, cursor, macro, index)
   2244 						index += offset
   2245 						if val == "" {
   2246 							// macro.should_not_output = true
   2247 							val = token_str // Fallback to the original token string.
   2248 						}
   2249 						strings.write_string(&builder, val)
   2250 					case .Literal:
   2251 						val := parse_literal(token_str)
   2252 						if val == "" {
   2253 							macro.should_not_output = true
   2254 							val = token_str // Fallback to the original token string.
   2255 						}
   2256 						strings.write_string(&builder, val)
   2257 					case .Punctuation:
   2258 						switch token_str[0] {
   2259 						case '#':
   2260 							macro.should_not_output = true
   2261 							strings.write_string(&builder, token_str)
   2262 						case '{':
   2263 							// If we hit a curly brace, we need to count how many we have.
   2264 							curly_parens += 1
   2265 							strings.write_string(&builder, token_str)
   2266 						case '}':
   2267 							curly_parens -= 1
   2268 							strings.write_string(&builder, token_str)
   2269 						case ',':
   2270 							if curly_parens == 0 {
   2271 								// If we are not in a parenthesis, we can't output a comma.
   2272 								macro.should_not_output = true
   2273 							}
   2274 							strings.write_string(&builder, token_str)
   2275 							strings.write_rune(&builder, ' ')
   2276 						case:
   2277 							// +, -, /, *, etc.
   2278 							strings.write_string(&builder, token_str)
   2279 						}
   2280 					case .Keyword:
   2281 						tokens_str := token_str
   2282 						tokens_count := 0
   2283 						for t in macro.tokens[index + 1:] {
   2284 							if clang.getTokenKind(t) == .Keyword {
   2285 								tokens_str = fmt.tprint(tokens_str, token_string(tu, t))
   2286 								tokens_count += 1
   2287 							} else {
   2288 								break
   2289 							}
   2290 						}
   2291 
   2292 						if keyword_string := translate_type_string(state, tokens_str); keyword_string != "" {
   2293 							strings.write_string(&builder, keyword_string)
   2294 							index += tokens_count
   2295 						} else {
   2296 							if keyword_string = translate_type_string(state, token_str); keyword_string != "" {
   2297 								strings.write_string(&builder, keyword_string)
   2298 							}
   2299 						}
   2300 					}
   2301 				}
   2302 				macro.val = strings.to_string(builder)
   2303 				if macro.val == "" {
   2304 					macro.should_not_output = true // Empty macro, we don't want to output it.
   2305 				}
   2306 			}
   2307 
   2308 			evaluate_macro :: proc(state: ^Gen_State, cursor: clang.Cursor, macro: ^Macro) {
   2309 				// I set this to true before evaluating the macro to avoid infinite recursion.
   2310 				// This is just a guard against a macro that calls itself.
   2311 				macro.has_been_evaluated = true
   2312 				if macro.is_function {
   2313 					evaluate_fn_macro(state, cursor, macro)
   2314 				} else {
   2315 					evaluate_nonfn_macro(state, cursor, macro)
   2316 				}
   2317 			}
   2318 
   2319 			if d.is_function {
   2320 				continue
   2321 			}
   2322 
   2323 			if !d.has_been_evaluated {
   2324 				evaluate_macro(&s, decl.cursor, &d)
   2325 			}
   2326 
   2327 			if d.val == "{}" || d.val == "{0}" {
   2328 				continue
   2329 			}
   2330 
   2331 			if d.comment != "" {
   2332 				fpln(f, d.comment)
   2333 			}
   2334 
   2335 			if d.should_not_output || d.original_name in s.remove_macros_lookup {
   2336 				// When we're happy with the parser this can change to a continue.
   2337 				fp(f, "// ")
   2338 			}
   2339 
   2340 			fpf(f, "%v%*s:: %v", d.name, max(d.whitespace_after_name, 1), "", d.val)
   2341 
   2342 			if d.side_comment != "" {
   2343 				fpf(f, "%*s%v", d.whitespace_before_side_comment, "", d.side_comment)
   2344 			}
   2345 
   2346 			fp(f, "\n")
   2347 
   2348 			if decl_idx < len(s.decls) - 1 {
   2349 				next := &s.decls[decl_idx + 1]
   2350 
   2351 				_, next_is_macro := next.variant.(Macro)
   2352 
   2353 				if !next_is_macro || cursor_location(next.cursor) != cursor_location(decl.cursor) + 1 {
   2354 					fp(f, "\n")
   2355 				}
   2356 			}
   2357 		}
   2358 	}
   2359 
   2360 	for _, index in s.macro_defines {
   2361 		decl := &s.decls[index]
   2362 		tu := clang.Cursor_getTranslationUnit(decl.cursor)
   2363 		clang.disposeTokens(tu, raw_data(decl.variant.(Macro).tokens), u32(len(decl.variant.(Macro).tokens)))
   2364 	}
   2365 
   2366 	//
   2367 	// Turn functions into groups that are separated by comments. If a comment
   2368 	// is before a function then it is used as a "group". If comments are to the
   2369 	// right of a function, then the group continues.
   2370 	//
   2371 	// Everything within a group shares the same padding between the name and
   2372 	// the `::`
   2373 	//
   2374 
   2375 	Function_Group :: struct {
   2376 		header_comment: string,
   2377 		functions: [dynamic]Function,
   2378 	}
   2379 
   2380 	groups: [dynamic]Function_Group
   2381 	curr_group: Function_Group
   2382 
   2383 	for &decl in s.decls {
   2384 		du := &decl.variant
   2385 		if f, f_ok := du.(Function); f_ok {
   2386 			if f.comment != "" {
   2387 				if len(curr_group.functions) > 0 {
   2388 					append(&groups, curr_group)
   2389 				}
   2390 
   2391 				curr_group = {
   2392 					header_comment = f.comment,
   2393 				}
   2394 			}
   2395 
   2396 			append(&curr_group.functions, f)
   2397 		}
   2398 	}
   2399 
   2400 	if len(curr_group.functions) > 0 {
   2401 		append(&groups, curr_group)
   2402 	}
   2403 
   2404 	if len(groups) > 0 {
   2405 		fmt.fprintfln(f, `@(default_calling_convention="c", link_prefix="%v")`, s.remove_function_prefix)
   2406 		fmt.fprintln(f, "foreign lib {")
   2407 
   2408 		for &g, gidx in groups {
   2409 			if g.header_comment != "" {
   2410 				if gidx != 0 {
   2411 					fp(f, "\n")
   2412 				}
   2413 
   2414 				output_comment(f, g.header_comment, "\t")
   2415 			}
   2416 
   2417 			longest_function_name: int
   2418 
   2419 			for &d in g.functions {
   2420 				if len(d.name) > longest_function_name {
   2421 					longest_function_name = len(d.name)
   2422 				}
   2423 			}
   2424 
   2425 			Formatted_Function :: struct {
   2426 				function: string,
   2427 				post_comment: string,
   2428 				attributes: []string,
   2429 			}
   2430 
   2431 			Formatted_Member :: struct {
   2432 				name: string,
   2433 				member: string,
   2434 				enum_member: ^Enum_Member,
   2435 			}
   2436 
   2437 			formatted_functions: [dynamic]Formatted_Function
   2438 
   2439 			for &d in g.functions {
   2440 				b := strings.builder_make()
   2441 				attributes := make([dynamic]string)
   2442 
   2443 				w :: strings.write_string
   2444 
   2445 				if d.link_name != "" {
   2446 					append(&attributes, fmt.tprintf("link_name=\"%s\"", d.link_name))
   2447 				}
   2448 
   2449 				w(&b, d.name)
   2450 
   2451 				for _ in 0..<longest_function_name-len(d.name) {
   2452 					strings.write_rune(&b, ' ')
   2453 				}
   2454 
   2455 				w(&b, " :: proc(")
   2456 
   2457 				for &p, i in d.parameters {
   2458 					n := vet_name(cursor_spelling(p))
   2459 
   2460 					type: string
   2461 					type_override_key := fmt.tprintf("%v.%v", d.original_name, n)
   2462 
   2463 					if type_override, type_override_ok := s.procedure_type_overrides[type_override_key]; type_override_ok {
   2464 						switch type_override {
   2465 						case "#by_ptr":
   2466 							w(&b, "#by_ptr ")
   2467 							type, _ = parse_type(&s, clang.getCursorType(p), {.By_Pointer})
   2468 						case "[^]":
   2469 							by_ptr := false
   2470 							type, by_ptr = parse_type(&s, clang.getCursorType(p), {.Pointer_To_Array})
   2471 							if by_ptr {
   2472 								w(&b, "#by_ptr ")
   2473 							}
   2474 						case:
   2475 							type = type_override
   2476 						}
   2477 					} else {
   2478 						by_ptr := false
   2479 						type, by_ptr = parse_type(&s, clang.getCursorType(p), nil)
   2480 						if by_ptr {
   2481 							w(&b, "#by_ptr ")
   2482 						}
   2483 					}
   2484 
   2485 					if len(n) != 0 {
   2486 						w(&b, n)
   2487 						w(&b, ": ")
   2488 					} else {
   2489 						w(&b, "_: ")
   2490 					}
   2491 
   2492 					w(&b, type)
   2493 
   2494 					if i != len(d.parameters) - 1 {
   2495 						w(&b, ", ")
   2496 					} else {
   2497 						if d.variadic {
   2498 							w(&b,", #c_vararg _: ..any")
   2499 						}
   2500 					}
   2501 				}
   2502 
   2503 				w(&b, ")")
   2504 
   2505 				return_type := clang.getResultType(clang.getCursorType(d.cursor))
   2506 				if return_type.kind != .Void {
   2507 					w(&b, " -> ")
   2508 
   2509 					return_type_string: string
   2510 
   2511 					if override, override_ok := s.procedure_type_overrides[d.original_name]; override_ok {
   2512 						switch override {
   2513 						case "[^]":
   2514 							return_type_string, _ = parse_type(&s, return_type, {.Pointer_To_Array})
   2515 						case:
   2516 							return_type_string = override
   2517 						}
   2518 					} else {
   2519 						return_type_string, _ = parse_type(&s, return_type, nil)
   2520 					}
   2521 
   2522 					w(&b, return_type_string)
   2523 				}
   2524 
   2525 				w(&b, " ---")
   2526 
   2527 				append(&formatted_functions, Formatted_Function {
   2528 					function = strings.to_string(b),
   2529 					post_comment = d.post_comment,
   2530 					attributes = attributes[:],
   2531 				})
   2532 			}
   2533 
   2534 			longest_formatted_function: int
   2535 
   2536 			for &ff in formatted_functions {
   2537 				if len(ff.function) < 90 && len(ff.function) > longest_formatted_function {
   2538 					longest_formatted_function = len(ff.function)
   2539 				}
   2540 			}
   2541 
   2542 			for &ff in formatted_functions {
   2543 				if len(ff.attributes) > 0 {
   2544 					fp(f, "\t")
   2545 					fp(f, fmt.tprintf("@(%s)", strings.join(ff.attributes[:], ", ")))
   2546 					fp(f, "\n")
   2547 				}
   2548 				fp(f, "\t")
   2549 				fp(f, ff.function)
   2550 
   2551 				if ff.post_comment != "" {
   2552 					for _ in 0..<(longest_formatted_function-len(ff.function)) {
   2553 						fp(f, ' ')
   2554 					}
   2555 
   2556 					fp(f, ' ')
   2557 					fp(f, ff.post_comment)
   2558 				}
   2559 
   2560 				fp(f, "\n")
   2561 			}
   2562 		}
   2563 
   2564 		fmt.fprintln(f, "}")
   2565 	}
   2566 }
   2567 
   2568 main :: proc() {
   2569 	permanent_arena: vmem.Arena
   2570 	permanent_allocator := vmem.arena_allocator(&permanent_arena)
   2571 	context.allocator = permanent_allocator
   2572 	context.temp_allocator = permanent_allocator
   2573 
   2574 	ensure(len(os.args) == 2, "Usage: bindgen directory")
   2575 	input_arg := os.args[1]
   2576 
   2577 	config_filename := "bindgen.sjson"
   2578 	config_dir: string
   2579 	if strings.has_suffix(input_arg, ".sjson") && os.is_file(input_arg) {
   2580 		config_filename = filepath.base(input_arg)
   2581 		config_dir = filepath.dir(input_arg, context.temp_allocator)
   2582 	} else if os.is_dir(input_arg) {
   2583 		config_dir = input_arg
   2584 	} else {
   2585 		fmt.panicf("%v is not a directory nor a valid config file", input_arg)
   2586 	}
   2587 
   2588 	// Config file is optional
   2589 	config: Config
   2590 
   2591 	default_output_folder := "output"
   2592 	default_package_name := "pkg"
   2593 
   2594 	if input_dir, input_dir_err := os2.open(input_arg); input_dir_err == nil {
   2595 		if stat, stat_err := input_dir.fstat(input_dir, context.allocator); stat_err == nil {
   2596 			default_output_folder = stat.name
   2597 			default_package_name = stat.name
   2598 		}
   2599 	}
   2600 
   2601 	if err := os.set_current_directory(config_dir); err != nil {
   2602 		fmt.panicf("failed to set current working directory: %v", err)
   2603 	}
   2604 
   2605 	if os.is_file(config_filename) {
   2606 		if config_data, config_data_ok := os.read_entire_file(config_filename); config_data_ok {
   2607 			config_err := json.unmarshal(config_data, &config, .SJSON)
   2608 			fmt.ensuref(
   2609 				config_err == nil,
   2610 				"Failed parsing config %v: %v",
   2611 				config_filename,
   2612 				config_err,
   2613 			)
   2614 		} else {
   2615 			fmt.ensuref(config_data_ok, "Failed parsing config %v", config_filename)
   2616 		}
   2617 	} else {
   2618 		config.inputs = {"."}
   2619 	}
   2620 
   2621 	if config.output_folder == "" {
   2622 		config.output_folder = default_output_folder
   2623 	}
   2624 
   2625 	if config.package_name == "" {
   2626 		config.package_name = default_package_name
   2627 	}
   2628 
   2629 	if config.remove_prefix != "" {
   2630 		panic(
   2631 			"Error in bindgen.sjson: remove_prefix has been split into remove_function_prefix and remove_type_prefix",
   2632 		)
   2633 	}
   2634 
   2635 	if len(config.rename_types) > 0 {
   2636 		panic("Error in bindgen.sjson: rename_types has been renamed to rename")
   2637 	}
   2638 
   2639 	input_files: [dynamic]string
   2640 
   2641 	for i in config.inputs {
   2642 		if os.is_dir(i) {
   2643 			input_folder, input_folder_err := os2.open(i)
   2644 			fmt.ensuref(input_folder_err == nil, "Failed opening folder %v: %v", i, input_folder_err)
   2645 			iter := os2.read_directory_iterator_create(input_folder)
   2646 
   2647 			for f in os2.read_directory_iterator(&iter) {
   2648 				if f.type != .Regular || slice.contains(config.ignore_inputs, f.name) {
   2649 					continue
   2650 				}
   2651 
   2652 				append(&input_files, fmt.tprintf("%v/%v", i, f.name))
   2653 			}
   2654 
   2655 			os2.close(input_folder)
   2656 		} else if os.is_file(i) {
   2657 			append(&input_files, i)
   2658 		} else {
   2659 			fmt.eprintfln("%v is neither directory or .h file", i)
   2660 		}
   2661 	}
   2662 
   2663 	if config.output_folder != "" && !os2.exists(config.output_folder) {
   2664 		make_dir_err := os2.make_directory_all(config.output_folder)
   2665 		fmt.ensuref(make_dir_err == nil, "Failed creating output directory %v: %v", config.output_folder, make_dir_err)
   2666 	}
   2667 
   2668 	for i in input_files {
   2669 		ext := filepath.ext(i)
   2670 		switch ext {
   2671 		case ".h":
   2672 			gen(i, config)
   2673 		case ".odin", ".lib", ".a", ".dll", ".dylib":
   2674 			// Bring along odin and library files
   2675 			name := filepath.base(i)
   2676 			os2.copy_file(fmt.tprintf("%v/%v", config.output_folder, name), i)
   2677 		}
   2678 	}
   2679 }