translate_macros.odin (7648B)
1 #+private file 2 package bindgen2 3 4 import "core:strings" 5 import "core:fmt" 6 import "core:log" 7 8 _ :: log 9 10 // TODO could we use a Declaration with some Raw_Macro type and just fix this in translate_process? 11 @(private="package") 12 Raw_Macro :: struct { 13 name: string, 14 tokens: []Raw_Macro_Token, 15 is_function_like: bool, 16 comment: string, 17 side_comment: string, 18 whitespace_before_side_comment: int, 19 whitespace_after_name: int, 20 original_line: int, 21 } 22 23 @(private="package") 24 Raw_Macro_Token :: struct { 25 value: string, 26 kind: Raw_Macro_Token_Kind, 27 } 28 29 // Same as Token_Kind in clang, but without 'Comment' 30 @(private="package") 31 Raw_Macro_Token_Kind :: enum { 32 Punctuation, 33 Keyword, 34 Identifier, 35 Literal, 36 } 37 38 @(private="package") 39 translate_macros :: proc(macros: []Raw_Macro, decls: Decl_List) { 40 existing_declaration_names: map[string]int 41 42 for d, i in decls { 43 existing_declaration_names[d.name] = i 44 } 45 46 macro_lookup: map[string]int 47 48 for m, i in macros { 49 macro_lookup[m.name] = i 50 } 51 52 for m, i in macros { 53 // Function-like macros are only used when figuring out a value of a non-function like macro. 54 // They will not have a value "of their own". 55 if m.is_function_like { 56 continue 57 } 58 59 odin_value := evaluate_macro(macros, macro_lookup, existing_declaration_names, i, {}) 60 61 if odin_value != "" && odin_value[0] != '{' { 62 def: Definition 63 if decl_idx, decl_exists := existing_declaration_names[odin_value]; decl_exists { 64 // We want the value of this macro to change if there is some trimming set in the config etc. 65 66 if decls[decl_idx].from_macro { 67 def = Macro_Name(odin_value) 68 } else { 69 def = Type_Name(odin_value) 70 } 71 } else { 72 def = Fixed_Value(odin_value) 73 } 74 75 add_decl(decls, { 76 name = m.name, 77 def = def, 78 comment_before = m.comment, 79 side_comment = m.side_comment, 80 explicit_whitespace_before_side_comment = m.whitespace_before_side_comment, 81 explicit_whitespace_after_name = m.whitespace_after_name, 82 original_line = m.original_line, 83 from_macro = true, 84 }) 85 86 existing_declaration_names[m.name] = len(decls) - 1 87 } 88 } 89 } 90 91 Macro_Index :: int 92 93 Evalulate_Macro_State :: struct { 94 cur_token: int, 95 tokens: []Raw_Macro_Token, 96 cur_macro: Raw_Macro, 97 cur_macro_index: Macro_Index, 98 macros: []Raw_Macro, 99 macro_lookup: map[string]Macro_Index, 100 params: map[string]string, 101 existing_declarations: map[string]int, 102 } 103 104 cur :: proc(ems: Evalulate_Macro_State) -> Raw_Macro_Token { 105 return ems.tokens[ems.cur_token] 106 } 107 108 adv :: proc(ems: ^Evalulate_Macro_State) { 109 ems.cur_token += 1 110 } 111 112 evaluate_macro :: proc(macros: []Raw_Macro, macro_lookup: map[string]Macro_Index, existing_declarations: map[string]int, mi: Macro_Index, args: []string) -> string { 113 ems := Evalulate_Macro_State { 114 cur_token = 0, 115 tokens = macros[mi].tokens, 116 cur_macro = macros[mi], 117 cur_macro_index = mi, 118 macros = macros, 119 macro_lookup = macro_lookup, 120 existing_declarations = existing_declarations, 121 } 122 123 if ems.cur_macro.is_function_like { 124 params := parse_parameter_list(&ems) 125 adv(&ems) 126 127 if len(params) != len(args) { 128 return "" 129 } 130 131 for a, i in args { 132 ems.params[params[i]] = a 133 } 134 } 135 136 curly_braces: int 137 138 b := strings.builder_make() 139 literal_type: Literal_Type_Info 140 notted: bool 141 142 for ems.cur_token < len(ems.tokens) { 143 t := cur(ems) 144 tv := t.value 145 146 switch t.kind { 147 case .Punctuation: 148 switch tv { 149 case "#": 150 return "" 151 152 case "{": 153 curly_braces += 1 154 p(&b, tv) 155 156 157 case "}": 158 curly_braces -= 1 159 p(&b, tv) 160 161 case ",": 162 if curly_braces == 0 { 163 return "" 164 } 165 166 p(&b, tv) 167 p(&b, ' ') 168 169 case "(", ")", "-", "*", "/", "+": 170 p(&b, tv) 171 172 case "~": 173 notted = true 174 } 175 case .Keyword: 176 return "" 177 case .Identifier: 178 if tv == "UINT64_MAX" { 179 notted = true 180 literal_type = .U64 181 break 182 } 183 184 if tv == "UINT32_MAX" { 185 notted = true 186 literal_type = .U32 187 break 188 } 189 190 if tv == "INT32_MAX" { 191 notted = true 192 literal_type = .I32 193 break 194 } 195 196 if tv == "INT64_MAX" { 197 notted = true 198 literal_type = .I64 199 break 200 } 201 202 if parse_identifier(&ems, &b) == false { 203 mapped, has_mapping := c_type_mapping[tv] 204 205 if has_mapping { 206 p(&b, mapped) 207 } else { 208 return "" 209 } 210 } 211 case .Literal: 212 if type, ok := parse_literal(&b, tv); ok == false { 213 return "" 214 } else { 215 literal_type = type 216 } 217 } 218 219 adv(&ems) 220 } 221 222 if notted { 223 switch literal_type { 224 case .None: 225 case .U32: return "max(u32)" 226 case .I32: return "max(i32)" 227 case .U64: return "max(u64)" 228 case .I64: return "max(i64)" 229 } 230 231 log.errorf("Unknown type: %v", ems.tokens) 232 } 233 234 return strings.to_string(b) 235 } 236 237 p :: fmt.sbprint 238 pf :: fmt.sbprintf 239 240 Literal_Type_Info :: enum { 241 None, 242 U32, 243 I32, 244 U64, 245 I64, 246 } 247 248 parse_literal :: proc(b: ^strings.Builder, val: string) -> (Literal_Type_Info, bool) { 249 if len(val) == 0 { 250 return {}, false 251 } 252 253 if val[0] >= '0' && val[0] <= '9' { 254 if len(val) == 1 { 255 p(b, val) 256 return {}, true 257 } 258 259 val_start := 0 260 hex := false 261 262 if val[1] == 'x' || val[1] == 'X' { 263 p(b, '0') 264 p(b, 'x') 265 hex = true 266 val_start = 2 267 } 268 269 end := len(val) - 1 270 271 l: int 272 u: int 273 274 // remove suffix chars such as ULL and f 275 LOOP: for ; end > 0; end -= 1 { 276 switch val[end] { 277 case 'L', 'l': 278 l += 1 279 continue LOOP 280 281 case 'U', 'u': 282 u += 1 283 continue LOOP 284 285 case 'F', 'f': 286 if hex { 287 break LOOP 288 } 289 // Floating point literals can have 'F' or 'f' suffixes. 290 continue LOOP 291 case: 292 // Not a suffix char. 293 break LOOP 294 } 295 } 296 297 ti: Literal_Type_Info 298 299 if l == 1 && u == 0 { 300 ti = .I32 301 } 302 303 if l == 0 && u == 1 || l == 1 && u == 1 { 304 ti = .U32 305 } 306 307 if l == 2 && u == 0 { 308 ti = .I64 309 } 310 311 if l == 2 && u == 1 { 312 ti = .U64 313 } 314 315 p(b, val[val_start:end + 1]) 316 return ti, true 317 } else if val[0] == '"' { 318 p(b, val) 319 return {}, true 320 } 321 return {}, false 322 } 323 324 parse_parameter_list :: proc(ems: ^Evalulate_Macro_State) -> []string { 325 t := cur(ems^) 326 327 if t.kind != .Punctuation || t.value != "(" { 328 return {} 329 } 330 331 paren_count := 1 332 333 adv(ems) 334 335 arg_builder := strings.builder_make() 336 args: [dynamic]string 337 338 args_loop: for ems.cur_token < len(ems.tokens) { 339 t = cur(ems^) 340 341 #partial switch t.kind { 342 case .Punctuation: 343 switch t.value { 344 case "(": 345 paren_count += 1 346 347 case ")": 348 paren_count -= 1 349 350 if paren_count == 0 { 351 append(&args, strings.to_string(arg_builder)) 352 arg_builder = strings.builder_make() 353 break args_loop 354 } 355 356 case ",": 357 append(&args, strings.to_string(arg_builder)) 358 arg_builder = strings.builder_make() 359 } 360 case .Identifier: 361 p(&arg_builder, t.value) 362 363 case .Literal: 364 p(&arg_builder, t.value) 365 } 366 367 adv(ems) 368 } 369 370 return args[:] 371 } 372 373 parse_identifier :: proc(ems: ^Evalulate_Macro_State, b: ^strings.Builder) -> bool { 374 t := cur(ems^) 375 assert(t.kind == .Identifier) 376 377 tv := t.value 378 379 // We are inside a function-like macro and this identifier is one of the parameter names: 380 // Replace the identifier with the argument! 381 if parameter_replacement, has_parameter_replacement := ems.params[tv]; has_parameter_replacement { 382 p(b, parameter_replacement) 383 return true 384 } 385 386 if tv in ems.existing_declarations { 387 p(b, tv) 388 return true 389 } 390 391 if inner_macro_idx, inner_macro_exists := ems.macro_lookup[tv]; inner_macro_exists { 392 inner_macro := ems.macros[inner_macro_idx] 393 394 args: []string 395 396 if inner_macro.is_function_like { 397 adv(ems) 398 args = parse_parameter_list(ems) 399 } 400 401 inner := evaluate_macro(ems.macros, ems.macro_lookup, ems.existing_declarations, inner_macro_idx, args) 402 403 if inner == "" { 404 return false 405 } 406 407 p(b, inner) 408 return true 409 } 410 411 return false 412 }