build.c (178660B)
1 /* See LICENSE for license details. */ 2 /* NOTE: inspired by nob: https://github.com/tsoding/nob.h */ 3 4 /* TODO(rnp): 5 * [ ]: refactor: allow @Expand to come before the table definition 6 * [ ]: cross compile/override baked compiler 7 * [ ]: msvc build doesn't detect out of date files correctly 8 * [ ]: seperate dwarf debug info 9 * [ ]: bug: need to account for member alignment in structs (eg. u64 in bake parameters) 10 */ 11 12 #define BEAMFORMER_IMPORT function 13 #define BASE_EXPORT function 14 #define BASE_IMPORT function 15 16 #include "util.h" 17 18 #define BUILD_DEPS_LIST \ 19 X("base_compiler.h") \ 20 X("base_linux.c") \ 21 X("base_platform.h") \ 22 X("base_types.h") \ 23 X("base_win32.c") \ 24 X("meta.h") \ 25 X("util.c") \ 26 X("util.h") \ 27 28 #include <stdarg.h> 29 #include <setjmp.h> 30 #include <stdio.h> 31 32 global char *g_argv0; 33 34 #define META_NAMESPACE_UPPER "Beamformer" 35 #define META_NAMESPACE_LOWER "beamformer" 36 37 #define OUTDIR "out" 38 #define OUTPUT(s) OUTDIR OS_PATH_SEPARATOR s 39 40 #if COMPILER_MSVC 41 #define COMMON_CFLAGS "-std:c11" 42 #define COMMON_FLAGS "-nologo", "-Fo:" OUTDIR "\\", "-Z7", "-Zo" 43 #define DEBUG_FLAGS "-Od", "-D_DEBUG" 44 #define OPTIMIZED_FLAGS "-O2" 45 #define EXTRA_FLAGS "" 46 #else 47 #define COMMON_CFLAGS "-std=c11" 48 #define COMMON_FLAGS "-pipe", "-Wall" 49 #define DEBUG_FLAGS "-O0", "-D_DEBUG", "-Wno-unused-function" 50 #define OPTIMIZED_FLAGS "-O3" 51 #define EXTRA_FLAGS_BASE "-Werror", "-Wextra", "-Wno-unused-parameter", \ 52 "-Wno-error=unused-function", "-fno-builtin" 53 #if COMPILER_GCC 54 #define EXTRA_FLAGS EXTRA_FLAGS_BASE, "-Wno-unused-variable" 55 #else 56 #define EXTRA_FLAGS EXTRA_FLAGS_BASE 57 #endif 58 #endif 59 60 #define is_aarch64 ARCH_ARM64 61 #define is_amd64 ARCH_X64 62 #define is_unix OS_LINUX 63 #define is_w32 OS_WINDOWS 64 #define is_clang COMPILER_CLANG 65 #define is_gcc COMPILER_GCC 66 #define is_msvc COMPILER_MSVC 67 68 #if OS_LINUX 69 70 #include <dirent.h> 71 #include <errno.h> 72 #include <string.h> 73 #include <sys/select.h> 74 #include <sys/wait.h> 75 76 #include "base_linux.c" 77 78 #define W32_DECL(x) 79 80 #define OS_SHARED_LINK_LIB(s) "lib" s ".so" 81 #define OS_SHARED_LIB(s) s ".so" 82 #define OS_STATIC_LIB(s) s ".a" 83 #define OS_MAIN "main_linux.c" 84 85 #elif OS_WINDOWS 86 87 #include <string.h> 88 89 #include "base_win32.c" 90 91 #define W32_DECL(x) x 92 93 #define OS_SHARED_LINK_LIB(s) s ".dll" 94 #define OS_SHARED_LIB(s) s ".dll" 95 #define OS_STATIC_LIB(s) s ".lib" 96 #define OS_MAIN "main_w32.c" 97 98 #else 99 #error Unsupported Platform 100 #endif 101 102 #if COMPILER_CLANG 103 #define COMPILER "clang" 104 #define CPP_COMPILER "clang++" 105 #define PREPROCESSOR "clang", "-E", "-P" 106 #elif COMPILER_MSVC 107 #define COMPILER "cl" 108 #define CPP_COMPILER "cl" 109 #define PREPROCESSOR "cl", "/EP" 110 #else 111 #define COMPILER "cc" 112 #define CPP_COMPILER "c++" 113 #define PREPROCESSOR "cc", "-E", "-P" 114 #endif 115 116 #if COMPILER_MSVC 117 #define LINK_LIB(name) name ".lib" 118 #define OBJECT(name) name ".obj" 119 #define OUTPUT_DLL(name) "/LD", "/Fe:", name 120 #define OUTPUT_LIB(name) "/out:" OUTPUT(name) 121 #define OUTPUT_EXE(name) "/Fe:", name 122 #define COMPILER_OUTPUT "/Fo:" 123 #define STATIC_LIBRARY_BEGIN(name) "lib", "/nologo", name 124 #else 125 #define LINK_LIB(name) "-l" name 126 #define OBJECT(name) name ".o" 127 #define OUTPUT_DLL(name) "-fPIC", "-shared", "-o", name 128 #define OUTPUT_LIB(name) OUTPUT(name) 129 #define OUTPUT_EXE(name) "-o", name 130 #define COMPILER_OUTPUT "-o" 131 #define STATIC_LIBRARY_BEGIN(name) "ar", "rc", name 132 #endif 133 134 #define shift(list, count) ((count)--, *(list)++) 135 136 #define cmd_append_count da_append_count 137 #define cmd_append(a, s, ...) da_append_count(a, s, ((char *[]){__VA_ARGS__}), \ 138 (i64)(sizeof((char *[]){__VA_ARGS__}) / sizeof(char *))) 139 140 DA_STRUCT(char *, Command); 141 142 typedef struct { 143 b32 bake_shaders; 144 b32 debug; 145 b32 generic; 146 b32 sanitize; 147 b32 tests; 148 b32 time; 149 } Config; 150 global Config config; 151 152 read_only str8 c_file_header = str8_comp("" 153 "/* See LICENSE for license details. */\n\n" 154 "// GENERATED CODE\n\n" 155 ); 156 157 #define BUILD_LOG_KINDS \ 158 X(Error, "\x1B[31m[ERROR]\x1B[0m ") \ 159 X(Warning, "\x1B[33m[WARNING]\x1B[0m ") \ 160 X(Generate, "\x1B[32m[GENERATE]\x1B[0m ") \ 161 X(Info, "\x1B[33m[INFO]\x1B[0m ") \ 162 X(Command, "\x1B[36m[COMMAND]\x1B[0m ") 163 #define X(t, ...) BuildLogKind_##t, 164 typedef enum {BUILD_LOG_KINDS BuildLogKind_Count} BuildLogKind; 165 #undef X 166 167 function void 168 build_log_base(BuildLogKind kind, char *format, va_list args) 169 { 170 #define X(t, pre) pre, 171 read_only char *prefixes[BuildLogKind_Count + 1] = {BUILD_LOG_KINDS "[INVALID] "}; 172 #undef X 173 FILE *out = kind == BuildLogKind_Error? stderr : stdout; 174 fputs(prefixes[Min(kind, BuildLogKind_Count)], out); 175 vfprintf(out, format, args); 176 fputc('\n', out); 177 } 178 179 #define build_log_failure(format, ...) build_log(BuildLogKind_Error, \ 180 "failed to build: " format, ##__VA_ARGS__) 181 #define build_log_error(...) build_log(BuildLogKind_Error, ##__VA_ARGS__) 182 #define build_log_generate(...) build_log(BuildLogKind_Generate, ##__VA_ARGS__) 183 #define build_log_info(...) build_log(BuildLogKind_Info, ##__VA_ARGS__) 184 #define build_log_command(...) build_log(BuildLogKind_Command, ##__VA_ARGS__) 185 #define build_log_warning(...) build_log(BuildLogKind_Warning, ##__VA_ARGS__) 186 187 function print_format(2, 3) void 188 build_log(BuildLogKind kind, char *format, ...) 189 { 190 va_list ap; 191 va_start(ap, format); 192 build_log_base(kind, format, ap); 193 va_end(ap); 194 } 195 196 #define build_fatal(fmt, ...) build_fatal_("%s: " fmt, __FUNCTION__, ##__VA_ARGS__) 197 function no_return print_format(1, 2) void 198 build_fatal_(char *format, ...) 199 { 200 va_list ap; 201 va_start(ap, format); 202 build_log_base(BuildLogKind_Error, format, ap); 203 va_end(ap); 204 os_exit(1); 205 } 206 207 function b32 208 str8_contains(str8 s, u8 byte) 209 { 210 b32 result = 0; 211 for (i64 i = 0 ; !result && i < s.length; i++) 212 result |= s.data[i] == byte; 213 return result; 214 } 215 216 function void 217 stream_push_command(Stream *s, CommandList *c) 218 { 219 if (!s->errors) { 220 for (i64 i = 0; i < c->count; i++) { 221 str8 item = str8_from_c_str(c->data[i]); 222 if (item.length) { 223 b32 escape = str8_contains(item, ' ') || str8_contains(item, '"'); 224 if (escape) stream_append_byte(s, '\''); 225 stream_append_str8(s, item); 226 if (escape) stream_append_byte(s, '\''); 227 if (i != c->count - 1) stream_append_byte(s, ' '); 228 } 229 } 230 } 231 } 232 233 function print_format(1, 2) char * 234 temp_sprintf(char *format, ...) 235 { 236 local_persist char buffer[4096]; 237 va_list ap; 238 va_start(ap, format); 239 vsnprintf(buffer, countof(buffer), format, ap); 240 va_end(ap); 241 return buffer; 242 } 243 244 #if OS_LINUX 245 246 function b32 247 os_rename_file(char *name, char *new) 248 { 249 b32 result = rename(name, new) != -1; 250 return result; 251 } 252 253 function b32 254 os_remove_file(char *name) 255 { 256 b32 result = remove(name) != -1; 257 return result; 258 } 259 260 function void 261 os_make_directory(char *name) 262 { 263 mkdir(name, 0770); 264 } 265 266 #define os_remove_directory(f) os_remove_directory_(AT_FDCWD, (f)) 267 function b32 268 os_remove_directory_(i32 base_fd, char *name) 269 { 270 /* POSix sucks */ 271 #ifndef DT_DIR 272 enum {DT_DIR = 4, DT_REG = 8, DT_LNK = 10}; 273 #endif 274 275 i32 dir_fd = openat(base_fd, name, O_DIRECTORY); 276 b32 result = dir_fd != -1 || errno == ENOTDIR || errno == ENOENT; 277 DIR *dir; 278 if (dir_fd != -1 && (dir = fdopendir(dir_fd))) { 279 struct dirent *dp; 280 while ((dp = readdir(dir))) { 281 switch (dp->d_type) { 282 case DT_LNK: 283 case DT_REG: 284 { 285 unlinkat(dir_fd, dp->d_name, 0); 286 }break; 287 case DT_DIR:{ 288 str8 dir_name = str8_from_c_str(dp->d_name); 289 if (!str8_equal(str8("."), dir_name) && !str8_equal(str8(".."), dir_name)) 290 os_remove_directory_(dir_fd, dp->d_name); 291 }break; 292 default:{ 293 build_log_warning("\"%s\": unknown directory entry kind: %d", dp->d_name, dp->d_type); 294 }break; 295 } 296 } 297 298 closedir(dir); 299 result = unlinkat(base_fd, name, AT_REMOVEDIR) == 0; 300 } 301 return result; 302 } 303 304 function str8 305 os_read_file_into_arena(const char *name, Arena *arena) 306 { 307 str8 result = {0}; 308 struct stat sb; 309 i32 fd = open(name, O_RDONLY); 310 if (fd >= 0 && fstat(fd, &sb) >= 0) { 311 result.data = push_array_no_zero(arena, u8, sb.st_size); 312 result.length = sb.st_size; 313 i64 total_read = 0; 314 do { 315 i64 rlen = read(fd, (u8 *)result.data + total_read, (u64)(result.length - total_read)); 316 if (rlen > 0) total_read += rlen; 317 } while (total_read != result.length && errno != EINTR); 318 319 if (total_read != result.length) { 320 arena_pop(arena, result.length); 321 result = (str8){0}; 322 } 323 } 324 if (fd >= 0) close(fd); 325 326 return result; 327 } 328 329 function u64 330 os_get_filetime(char *file) 331 { 332 struct stat sb; 333 u64 result = (u64)-1; 334 if (stat(file, &sb) != -1) 335 result = (u64)sb.st_mtim.tv_sec; 336 return result; 337 } 338 339 function iptr 340 os_spawn_process(CommandList *cmd, Stream sb) 341 { 342 pid_t result = fork(); 343 switch (result) { 344 case -1: build_fatal("failed to fork command: %s: %s", cmd->data[0], strerror(errno)); break; 345 case 0: { 346 if (execvp(cmd->data[0], cmd->data) == -1) 347 build_fatal("failed to exec command: %s: %s", cmd->data[0], strerror(errno)); 348 unreachable(); 349 } break; 350 } 351 return (iptr)result; 352 } 353 354 function b32 355 os_wait_close_process(iptr handle) 356 { 357 b32 result = 0; 358 for (;;) { 359 i32 status; 360 iptr wait_pid = (iptr)waitpid((i32)handle, &status, 0); 361 if (wait_pid == -1) 362 build_fatal("failed to wait on child process: %s", strerror(errno)); 363 if (wait_pid == handle) { 364 if (WIFEXITED(status)) { 365 status = WEXITSTATUS(status); 366 /* TODO(rnp): logging */ 367 result = status == 0; 368 break; 369 } 370 if (WIFSIGNALED(status)) { 371 /* TODO(rnp): logging */ 372 result = 0; 373 break; 374 } 375 } else { 376 /* TODO(rnp): handle multiple children */ 377 InvalidCodePath; 378 } 379 } 380 return result; 381 } 382 383 #elif OS_WINDOWS 384 385 enum { 386 MOVEFILE_REPLACE_EXISTING = 0x01, 387 388 FILE_ATTRIBUTE_DIRECTORY = 0x10, 389 390 ERROR_FILE_NOT_FOUND = 0x02, 391 ERROR_PATH_NOT_FOUND = 0x03, 392 }; 393 394 #pragma pack(push, 1) 395 typedef struct { 396 u32 file_attributes; 397 u64 creation_time; 398 u64 last_access_time; 399 u64 last_write_time; 400 u64 file_size; 401 u64 reserved; 402 c8 file_name[260]; 403 c8 alternate_file_name[14]; 404 u32 file_type; 405 u32 creator_type; 406 u16 finder_flag; 407 } w32_find_data; 408 #pragma pack(pop) 409 410 W32(b32) CreateDirectoryA(c8 *, void *); 411 W32(b32) CreateProcessA(u8 *, u8 *, iptr, iptr, b32, u32, iptr, u8 *, iptr, iptr); 412 W32(b32) FindClose(iptr); 413 W32(iptr) FindFirstFileA(c8 *, w32_find_data *); 414 W32(b32) FindNextFileA(iptr, w32_find_data *); 415 W32(b32) GetExitCodeProcess(iptr, u32 *); 416 W32(b32) GetFileTime(iptr, iptr, iptr, iptr); 417 W32(b32) MoveFileExA(c8 *, c8 *, u32); 418 W32(b32) RemoveDirectoryA(c8 *); 419 420 function void 421 os_make_directory(char *name) 422 { 423 CreateDirectoryA(name, 0); 424 } 425 426 function str8 427 os_read_file_into_arena(const char *name, Arena *arena) 428 { 429 str8 result = {0}; 430 w32_file_info fileinfo; 431 iptr h = CreateFileA((c8 *)name, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); 432 if (h >= 0 && GetFileInformationByHandle(h, &fileinfo)) { 433 u64 filesize = (i64)fileinfo.nFileSizeHigh << 32; 434 filesize |= (i64)fileinfo.nFileSizeLow; 435 if (filesize <= S32_MAX) { 436 result.data = push_array_no_zero(arena, u8, filesize); 437 result.length = filesize; 438 i32 rlen = 0; 439 if (!ReadFile(h, result.data, (i32)filesize, &rlen, 0) || rlen != filesize) { 440 arena_pop(arena, filesize); 441 result = (str8){0}; 442 } 443 } 444 } 445 if (h >= 0) CloseHandle(h); 446 447 return result; 448 } 449 450 function b32 451 os_remove_directory(char *name) 452 { 453 w32_find_data find_data[1]; 454 char *search = temp_sprintf(".\\%s\\*", name); 455 iptr handle = FindFirstFileA(search, find_data); 456 b32 result = 1; 457 if (handle != INVALID_FILE) { 458 do { 459 str8 file_name = str8_from_c_str(find_data->file_name); 460 if (!str8_equal(str8("."), file_name) && !str8_equal(str8(".."), file_name)) { 461 char *full_path = temp_sprintf("%s" OS_PATH_SEPARATOR "%s", name, find_data->file_name); 462 if (find_data->file_attributes & FILE_ATTRIBUTE_DIRECTORY) { 463 char *wow_w32_is_even_worse_than_POSix = strdup(full_path); 464 os_remove_directory(wow_w32_is_even_worse_than_POSix); 465 free(wow_w32_is_even_worse_than_POSix); 466 } else { 467 DeleteFileA(full_path); 468 } 469 } 470 } while (FindNextFileA(handle, find_data)); 471 FindClose(handle); 472 } else { 473 i32 error = GetLastError(); 474 result = error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND; 475 } 476 RemoveDirectoryA(name); 477 return result; 478 } 479 480 function b32 481 os_rename_file(char *name, char *new) 482 { 483 b32 result = MoveFileExA(name, new, MOVEFILE_REPLACE_EXISTING) != 0; 484 return result; 485 } 486 487 function b32 488 os_remove_file(char *name) 489 { 490 b32 result = DeleteFileA(name); 491 return result; 492 } 493 494 function u64 495 os_get_filetime(char *file) 496 { 497 u64 result = (u64)-1; 498 iptr h = CreateFileA(file, 0, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); 499 if (h != INVALID_FILE) { 500 union { struct { u32 low, high; }; u64 U64; } w32_filetime; 501 GetFileTime(h, 0, 0, (iptr)&w32_filetime); 502 result = w32_filetime.U64; 503 CloseHandle(h); 504 } 505 return result; 506 } 507 508 function iptr 509 os_spawn_process(CommandList *cmd, Stream sb) 510 { 511 struct { 512 u32 cb; 513 u8 *reserved, *desktop, *title; 514 u32 x, y, x_size, y_size, x_count_chars, y_count_chars; 515 u32 fill_attr, flags; 516 u16 show_window, reserved_2; 517 u8 *reserved_3; 518 iptr std_input, std_output, std_error; 519 } w32_startup_info = { 520 .cb = sizeof(w32_startup_info), 521 .flags = 0x100, 522 .std_input = GetStdHandle(STD_INPUT_HANDLE), 523 .std_output = GetStdHandle(STD_OUTPUT_HANDLE), 524 .std_error = GetStdHandle(STD_ERROR_HANDLE), 525 }; 526 527 struct { 528 iptr phandle, thandle; 529 u32 pid, tid; 530 } w32_process_info = {0}; 531 532 /* TODO(rnp): warn if we need to clamp last string */ 533 sb.widx = Min(sb.widx, (i32)(KB(32) - 1)); 534 if (sb.widx < sb.cap) sb.data[sb.widx] = 0; 535 else sb.data[sb.widx - 1] = 0; 536 537 iptr result = INVALID_FILE; 538 if (CreateProcessA(0, sb.data, 0, 0, 1, 0, 0, 0, (iptr)&w32_startup_info, 539 (iptr)&w32_process_info)) 540 { 541 CloseHandle(w32_process_info.thandle); 542 result = w32_process_info.phandle; 543 } 544 return result; 545 } 546 547 function b32 548 os_wait_close_process(iptr handle) 549 { 550 b32 result = WaitForSingleObject(handle, (u32)-1) != 0xFFFFFFFFUL; 551 if (result) { 552 u32 status; 553 GetExitCodeProcess(handle, &status); 554 result = status == 0; 555 } 556 CloseHandle(handle); 557 return result; 558 } 559 560 #endif 561 562 #define needs_rebuild(b, ...) needs_rebuild_(b, ((char *[]){__VA_ARGS__}), \ 563 (sizeof((char *[]){__VA_ARGS__}) / sizeof(char *))) 564 function b32 565 needs_rebuild_(char *binary, char *deps[], i64 deps_count) 566 { 567 u64 binary_filetime = os_get_filetime(binary); 568 u64 argv0_filetime = os_get_filetime(g_argv0); 569 b32 result = (binary_filetime == (u64)-1) | (argv0_filetime > binary_filetime); 570 for (i64 i = 0; i < deps_count; i++) { 571 u64 filetime = os_get_filetime(deps[i]); 572 result |= (filetime == (u64)-1) | (filetime > binary_filetime); 573 } 574 return result; 575 } 576 577 function b32 578 run_synchronous(Arena *a, CommandList *command) 579 { 580 Stream sb = arena_stream(a); 581 stream_push_command(&sb, command); 582 build_log_command("%.*s", (i32)sb.widx, sb.data); 583 return os_wait_close_process(os_spawn_process(command, sb)); 584 } 585 586 function b32 587 use_sanitization(void) 588 { 589 return config.sanitize && !is_msvc && !(is_w32 && is_gcc); 590 } 591 592 function void 593 cmd_base(Arena *a, CommandList *c, b32 cpp, b32 debug) 594 { 595 Config *o = &config; 596 597 cmd_append(a, c, cpp ? CPP_COMPILER : COMPILER); 598 599 if (!is_msvc) { 600 /* TODO(rnp): support cross compiling with clang */ 601 if (!o->generic) cmd_append(a, c, "-march=native"); 602 else if (is_amd64) cmd_append(a, c, "-march=x86-64-v3", "-msse4.1"); 603 else if (is_aarch64) cmd_append(a, c, "-march=armv8"); 604 } 605 606 if (!cpp) cmd_append(a, c, COMMON_CFLAGS); 607 cmd_append(a, c, COMMON_FLAGS); 608 if (debug) cmd_append(a, c, DEBUG_FLAGS); 609 else cmd_append(a, c, OPTIMIZED_FLAGS); 610 611 /* NOTE: ancient gcc bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80454 */ 612 if (is_gcc) cmd_append(a, c, "-Wno-missing-braces"); 613 614 if (!is_msvc) cmd_append(a, c, "-fms-extensions"); 615 616 if (debug && is_unix) cmd_append(a, c, "-gdwarf-4"); 617 618 /* NOTE(rnp): need to avoid w32-gcc for ci */ 619 b32 sanitize = use_sanitization(); 620 if (sanitize) cmd_append(a, c, "-fsanitize=address,undefined"); 621 if (!sanitize && o->sanitize) build_log_warning("santizers not supported with this compiler"); 622 } 623 624 function void 625 check_rebuild_self(Arena *arena, i32 argc, char *argv[]) 626 { 627 char *binary = shift(argv, argc); 628 #define X(file, ...) file, 629 char *deps[] = {__FILE__, BUILD_DEPS_LIST}; 630 #undef X 631 if (needs_rebuild_(binary, deps, countof(deps))) { 632 Stream name_buffer = arena_stream(arena); 633 stream_append_str8s(&name_buffer, str8_from_c_str(binary), str8(".old")); 634 char *old_name = (char *)arena_stream_commit_zero(arena, &name_buffer).data; 635 636 if (!os_rename_file(binary, old_name)) 637 build_fatal("failed to move: %s -> %s", binary, old_name); 638 639 CommandList c = {0}; 640 cmd_base(arena, &c, 0, 0); 641 cmd_append(arena, &c, EXTRA_FLAGS); 642 if (!is_msvc) cmd_append(arena, &c, "-Wno-unused-function"); 643 cmd_append(arena, &c, __FILE__, OUTPUT_EXE(binary)); 644 if (is_msvc) cmd_append(arena, &c, "/link", "-incremental:no", "-opt:ref"); 645 cmd_append(arena, &c, (void *)0); 646 if (!run_synchronous(arena, &c)) { 647 os_rename_file(old_name, binary); 648 build_fatal("failed to rebuild self"); 649 } 650 os_remove_file(old_name); 651 652 c.count = 0; 653 cmd_append(arena, &c, binary); 654 cmd_append_count(arena, &c, argv, argc); 655 cmd_append(arena, &c, (void *)0); 656 if (!run_synchronous(arena, &c)) 657 os_exit(1); 658 659 os_exit(0); 660 } 661 } 662 663 function void 664 usage(char *argv0) 665 { 666 printf("%s [--bake-shaders] [--debug] [--sanitize] [--time]\n" 667 " --debug: dynamically link and build with debug symbols\n" 668 " --generic: compile for a generic target (x86-64-v3 or armv8 with NEON)\n" 669 " --sanitize: build with ASAN and UBSAN\n" 670 " --tests: also build programs in tests/\n" 671 " --time: print build time\n" 672 , argv0); 673 os_exit(0); 674 } 675 676 function void 677 parse_config(i32 argc, char *argv[]) 678 { 679 char *argv0 = shift(argv, argc); 680 while (argc > 0) { 681 char *arg = shift(argv, argc); 682 str8 str = str8_from_c_str(arg); 683 if (str8_equal(str, str8("--bake-shaders"))) { 684 config.bake_shaders = 1; 685 } else if (str8_equal(str, str8("--debug"))) { 686 config.debug = 1; 687 } else if (str8_equal(str, str8("--generic"))) { 688 config.generic = 1; 689 } else if (str8_equal(str, str8("--sanitize"))) { 690 config.sanitize = 1; 691 } else if (str8_equal(str, str8("--tests"))) { 692 config.tests = 1; 693 } else if (str8_equal(str, str8("--time"))) { 694 config.time = 1; 695 } else { 696 usage(argv0); 697 } 698 } 699 } 700 701 /* NOTE(rnp): produce pdbs on w32 */ 702 function void 703 cmd_pdb(Arena *a, CommandList *cmd, char *name) 704 { 705 if (is_w32 && is_clang) { 706 cmd_append(a, cmd, "-fuse-ld=lld", "-g", "-gcodeview", "-Wl,--pdb="); 707 } else if (is_msvc) { 708 Stream sb = arena_stream(a); 709 stream_append_str8s(&sb, str8("-PDB:"), str8_from_c_str(name), str8(".pdb")); 710 char *pdb = (char *)arena_stream_commit_zero(a, &sb).data; 711 cmd_append(a, cmd, "/link", "-incremental:no", "-opt:ref", "-DEBUG", pdb); 712 } 713 } 714 715 function void 716 git_submodule_update(Arena *a, char *name) 717 { 718 Stream sb = arena_stream(a); 719 stream_append_str8s(&sb, str8_from_c_str(name), str8(OS_PATH_SEPARATOR), str8(".git")); 720 arena_stream_commit_zero(a, &sb); 721 722 CommandList git = {0}; 723 /* NOTE(rnp): cryptic bs needed to get a simple exit code if name is dirty */ 724 cmd_append(a, &git, "git", "diff-index", "--quiet", "HEAD", "--", name, (void *)0); 725 if (!os_file_exists((c8 *)sb.data) || !run_synchronous(a, &git)) { 726 git.count = 1; 727 cmd_append(a, &git, "submodule", "update", "--init", "--depth=1", name, (void *)0); 728 if (!run_synchronous(a, &git)) 729 build_fatal("failed to clone required module: %s", name); 730 } 731 } 732 733 function b32 734 build_shared_library(Arena *a, CommandList cc, char *name, char *output, char **libs, i64 libs_count, char **srcs, i64 srcs_count) 735 { 736 cmd_append_count(a, &cc, srcs, srcs_count); 737 cmd_append(a, &cc, OUTPUT_DLL(output)); 738 cmd_pdb(a, &cc, name); 739 cmd_append_count(a, &cc, libs, libs_count); 740 cmd_append(a, &cc, (void *)0); 741 b32 result = run_synchronous(a, &cc); 742 if (!result) build_log_failure("%s", output); 743 return result; 744 } 745 746 function b32 747 cc_single_file(Arena *a, CommandList cc, char *exe, char *src, char *dest, char **tail, i64 tail_count) 748 { 749 char *executable[] = {src, is_msvc? "/Fe:" : "-o", dest}; 750 char *object[] = {is_msvc? "/c" : "-c", src, is_msvc? "/Fo:" : "-o", dest}; 751 752 cmd_append_count(a, &cc, exe? executable : object, 753 exe? countof(executable) : countof(object)); 754 if (exe) cmd_pdb(a, &cc, exe); 755 cmd_append_count(a, &cc, tail, tail_count); 756 cmd_append(a, &cc, (void *)0); 757 b32 result = run_synchronous(a, &cc); 758 if (!result) build_log_failure("%s", dest); 759 return result; 760 } 761 762 function b32 763 build_static_library_from_objects(Arena *a, char *name, char **flags, i64 flags_count, char **objects, i64 count) 764 { 765 CommandList ar = {0}; 766 cmd_append(a, &ar, STATIC_LIBRARY_BEGIN(name)); 767 cmd_append_count(a, &ar, flags, flags_count); 768 cmd_append_count(a, &ar, objects, count); 769 cmd_append(a, &ar, (void *)0); 770 b32 result = run_synchronous(a, &ar); 771 if (!result) build_log_failure("%s", name); 772 return result; 773 } 774 775 function b32 776 build_static_library(Arena *a, CommandList cc, char *name, char **deps, char **outputs, i64 count) 777 { 778 /* TODO(rnp): refactor to not need outputs */ 779 b32 result = 1; 780 for (i64 i = 0; i < count; i++) 781 result &= cc_single_file(a, cc, 0, deps[i], outputs[i], 0, 0); 782 if (result) result = build_static_library_from_objects(a, name, 0, 0, outputs, count); 783 return result; 784 } 785 786 function b32 787 build_raylib(Arena *a) 788 { 789 b32 result = 1, shared = config.debug; 790 char *libraylib = shared ? OS_SHARED_LINK_LIB("raylib") : OUTPUT_LIB(OS_STATIC_LIB("raylib")); 791 if (needs_rebuild(libraylib, "external/raylib")) { 792 git_submodule_update(a, "external/raylib"); 793 794 CommandList cc = {0}; 795 cmd_base(a, &cc, 0, config.debug); 796 if (is_unix) cmd_append(a, &cc, "-D_GLFW_X11"); 797 cmd_append(a, &cc, "-DPLATFORM_DESKTOP_GLFW"); 798 if (!is_msvc) cmd_append(a, &cc, "-Wno-unused-but-set-variable"); 799 cmd_append(a, &cc, "-Iexternal/include", "-Iexternal/raylib/src", "-Iexternal/raylib/src/external/glfw/include"); 800 #define RAYLIB_SOURCES \ 801 X(rglfw) \ 802 X(rshapes) \ 803 X(rtext) \ 804 X(rtextures) \ 805 X(utils) 806 #define X(name) "external/raylib/src/" #name ".c", 807 char *srcs[] = {"external/rcore_extended.c", RAYLIB_SOURCES}; 808 #undef X 809 #define X(name) OUTPUT(OBJECT(#name)), 810 char *outs[] = {OUTPUT(OBJECT("rcore_extended")), RAYLIB_SOURCES}; 811 #undef X 812 813 if (shared) { 814 char *libs[] = {LINK_LIB("user32"), LINK_LIB("shell32"), LINK_LIB("gdi32"), LINK_LIB("winmm")}; 815 i64 libs_count = is_w32 ? countof(libs) : 0; 816 cmd_append(a, &cc, "-DBUILD_LIBTYPE_SHARED", "-D_GLFW_BUILD_DLL"); 817 result = build_shared_library(a, cc, "raylib", libraylib, libs, libs_count, srcs, countof(srcs)); 818 } else { 819 result = build_static_library(a, cc, libraylib, srcs, outs, countof(srcs)); 820 } 821 } 822 return result; 823 } 824 825 function b32 826 build_glslang(Arena *a) 827 { 828 b32 result = 1; 829 char *lib = OUTPUT_LIB(OS_STATIC_LIB("glslang")); 830 if (needs_rebuild(lib, "external/glslang", "external/glslang_local/glslang.cpp")) { 831 git_submodule_update(a, "external/glslang"); 832 833 // NOTE(rnp): do not build this with debug symbols. The size explodes because c++ 834 CommandList cc = {0}; 835 cmd_base(a, &cc, 1, 0); 836 cmd_append(a, &cc, "-std=c++17", "-fno-rtti", "-fno-exceptions", "-Wno-unused-but-set-variable"); 837 cmd_append(a, &cc, "-Iexternal/glslang_local", "-Iexternal/glslang"); 838 839 #if OS_WINDOWS 840 #define GLSLANG_SOURCES_OS X(ossource, "glslang/glslang/OSDependent/Windows/") 841 #else 842 #define GLSLANG_SOURCES_OS 843 #endif 844 845 #define GLSLANG_SOURCES_COMMON \ 846 X(glslang, "glslang_local/") \ 847 X(spirv_c_interface, "glslang/SPIRV/CInterface/") \ 848 849 #define GLSLANG_SOURCES \ 850 GLSLANG_SOURCES_COMMON \ 851 GLSLANG_SOURCES_OS \ 852 853 #define X(name, extra) "external/" extra #name ".cpp", 854 char *srcs[] = {GLSLANG_SOURCES}; 855 #undef X 856 #define X(name, ...) OUTPUT(OBJECT(#name)), 857 char *outs[] = {GLSLANG_SOURCES}; 858 #undef X 859 860 result = build_static_library(a, cc, lib, srcs, outs, countof(srcs)); 861 } 862 return result; 863 } 864 865 function b32 866 build_helper_library(Arena *arena) 867 { 868 CommandList cc = {0}; 869 cmd_base(arena, &cc, 0, 0); 870 cmd_append(arena, &cc, EXTRA_FLAGS); 871 872 ///////////// 873 // library 874 char *library = OUTPUT(OS_SHARED_LIB("ogl_beamformer_lib")); 875 char *libs[] = {LINK_LIB("Synchronization")}; 876 i64 libs_count = is_w32 ? countof(libs) : 0; 877 878 if (!is_msvc) cmd_append(arena, &cc, "-Wno-unused-function"); 879 b32 result = build_shared_library(arena, cc, "ogl_beamformer_lib", library, 880 libs, libs_count, (char *[]){"lib/ogl_beamformer_lib.c"}, 1); 881 return result; 882 } 883 884 function void 885 cmd_beamformer_base(Arena *a, CommandList *c) 886 { 887 cmd_base(a, c, 0, config.debug); 888 cmd_append(a, c, "-Iexternal/include"); 889 cmd_append(a, c, EXTRA_FLAGS); 890 cmd_append(a, c, config.bake_shaders? "-DBakeShaders=1" : "-DBakeShaders=0"); 891 if (config.debug) cmd_append(a, c, "-DBEAMFORMER_DEBUG", "-DBEAMFORMER_RENDERDOC_HOOKS"); 892 893 /* NOTE(rnp): impossible to autodetect on GCC versions < 14 (ci has 13) */ 894 cmd_append(a, c, use_sanitization() ? "-DASAN_ACTIVE=1" : "-DASAN_ACTIVE=0"); 895 } 896 897 function b32 898 build_beamformer_main(Arena *arena) 899 { 900 CommandList c = {0}; 901 cmd_beamformer_base(arena, &c); 902 903 cmd_append(arena, &c, OS_MAIN, OUTPUT_EXE("ogl")); 904 cmd_pdb(arena, &c, "ogl"); 905 if (config.debug) { 906 if (!is_w32) cmd_append(arena, &c, "-Wl,--export-dynamic", "-Wl,-rpath,."); 907 if (!is_msvc) cmd_append(arena, &c, "-L."); 908 cmd_append(arena, &c, LINK_LIB("raylib")); 909 } else { 910 if (!is_msvc) cmd_append(arena, &c, "-flto"); 911 cmd_append(arena, &c, OUTPUT(OS_STATIC_LIB("raylib"))); 912 } 913 // TODO(rnp): not sure how to do this with msvc. we don't want a runtime dependence on libc++ 914 cmd_append(arena, &c, OUTPUT(OS_STATIC_LIB("glslang")), "-Wl,-Bstatic", "-lstdc++", "-Wl,-Bdynamic"); 915 916 if (!is_msvc) cmd_append(arena, &c, "-lm"); 917 if (is_unix) cmd_append(arena, &c, "-lGL"); 918 919 if (is_w32) { 920 cmd_append(arena, &c, LINK_LIB("user32"), LINK_LIB("shell32"), LINK_LIB("gdi32"), 921 LINK_LIB("opengl32"), LINK_LIB("winmm"), LINK_LIB("Synchronization")); 922 if (!is_msvc) cmd_append(arena, &c, "-Wl,--out-implib," OUTPUT(OS_STATIC_LIB("main"))); 923 } 924 925 cmd_append(arena, &c, (void *)0); 926 927 return run_synchronous(arena, &c); 928 } 929 930 function b32 931 build_beamformer_as_library(Arena *arena) 932 { 933 CommandList cc = {0}; 934 cmd_beamformer_base(arena, &cc); 935 936 if (is_msvc) { 937 build_static_library_from_objects(arena, OUTPUT_LIB(OS_STATIC_LIB("main")), 938 arg_list(char *, "/def", "/name:ogl.exe"), 939 arg_list(char *, OUTPUT(OBJECT("main_w32")))); 940 } 941 942 char *library = OS_SHARED_LIB("beamformer"); 943 char *libs[] = {!is_msvc? "-L." : "", LINK_LIB("raylib"), LINK_LIB("gdi32"), 944 LINK_LIB("shell32"), LINK_LIB("user32"), LINK_LIB("opengl32"), 945 LINK_LIB("winmm"), LINK_LIB("Synchronization"), OUTPUT("main.lib")}; 946 i64 libs_count = is_w32 ? countof(libs) : 0; 947 cmd_append(arena, &cc, "-D_BEAMFORMER_DLL"); 948 b32 result = build_shared_library(arena, cc, "beamformer", library, 949 libs, libs_count, arg_list(char *, "beamformer_core.c")); 950 return result; 951 } 952 953 function b32 954 build_tests(Arena *arena) 955 { 956 CommandList cc = {0}; 957 cmd_base(arena, &cc, 0, config.debug); 958 cmd_append(arena, &cc, EXTRA_FLAGS); 959 960 #define TEST_PROGRAMS \ 961 X("throughput", LINK_LIB("m"), LINK_LIB("zstd"), W32_DECL(LINK_LIB("Synchronization"))) \ 962 X("decode", LINK_LIB("m"), W32_DECL(LINK_LIB("Synchronization"))) \ 963 964 os_make_directory(OUTPUT("tests")); 965 if (!is_msvc) cmd_append(arena, &cc, "-Wno-unused-function"); 966 cmd_append(arena, &cc, "-I.", "-Ilib"); 967 968 b32 result = 1; 969 i64 cc_count = cc.count; 970 #define X(prog, ...) \ 971 result &= cc_single_file(arena, cc, prog, "tests" OS_PATH_SEPARATOR prog ".c", \ 972 OUTPUT("tests" OS_PATH_SEPARATOR prog), \ 973 arg_list(char *, ##__VA_ARGS__)); \ 974 cc.count = cc_count; 975 TEST_PROGRAMS 976 #undef X 977 return result; 978 } 979 980 typedef struct { 981 str8 *data; 982 da_count count; 983 da_count capacity; 984 } str8_list; 985 986 function str8 987 str8_chop(str8 *in, i64 count) 988 { 989 count = Clamp(count, 0, in->length); 990 str8 result = {.data = in->data, .length = count}; 991 in->data += count; 992 in->length -= count; 993 return result; 994 } 995 996 function void 997 str8_split(str8 str, str8 *left, str8 *right, u8 byte) 998 { 999 i64 i; 1000 for (i = 0; i < str.length; i++) if (str.data[i] == byte) break; 1001 1002 if (left) *left = (str8){.data = str.data, .length = i}; 1003 if (right) { 1004 right->data = str.data + i + 1; 1005 right->length = Max(0, str.length - (i + 1)); 1006 } 1007 } 1008 1009 function str8 1010 str8_trim(str8 in) 1011 { 1012 str8 result = in; 1013 for (i64 i = 0; i < in.length && *result.data == ' '; i++) result.data++; 1014 result.length -= result.data - in.data; 1015 for (; result.length > 0 && result.data[result.length - 1] == ' '; result.length--); 1016 return result; 1017 } 1018 1019 typedef struct { 1020 Stream stream; 1021 Arena *scratch; 1022 i32 indentation_level; 1023 } MetaprogramContext; 1024 1025 function b32 1026 meta_write_and_reset(MetaprogramContext *m, char *file) 1027 { 1028 b32 result = os_write_new_file(file, stream_to_str8(&m->stream)); 1029 if (!result) build_log_failure("%s", file); 1030 m->stream.widx = 0; 1031 m->indentation_level = 0; 1032 return result; 1033 } 1034 1035 #define meta_push(m, ...) meta_push_(m, arg_list(str8, __VA_ARGS__)) 1036 function void 1037 meta_push_(MetaprogramContext *m, str8 *items, i64 count) 1038 { 1039 stream_append_str8s_(&m->stream, items, count); 1040 } 1041 1042 #define meta_pad(m, b, n) stream_pad(&(m)->stream, (b), (n)) 1043 #define meta_indent(m) meta_pad((m), '\t', (m)->indentation_level) 1044 #define meta_begin_line(m, ...) meta_indent(m), meta_push(m, __VA_ARGS__) 1045 #define meta_end_line(m, ...) meta_push(m, ##__VA_ARGS__, str8("\n")) 1046 #define meta_push_line(m, ...) meta_indent(m), meta_push(m, ##__VA_ARGS__, str8("\n")) 1047 #define meta_begin_scope(m, ...) meta_push_line(m, __VA_ARGS__), (m)->indentation_level++ 1048 #define meta_end_scope(m, ...) (m)->indentation_level--, meta_push_line(m, __VA_ARGS__) 1049 #define meta_push_f64(m, n) stream_append_f64(&(m)->stream, (n), 1000000) 1050 #define meta_push_u64(m, n) stream_append_u64(&(m)->stream, (n)) 1051 #define meta_push_i64(m, n) stream_append_i64(&(m)->stream, (n)) 1052 #define meta_push_u64_hex(m, n) stream_append_hex_u64(&(m)->stream, (n)) 1053 #define meta_push_u64_hex_width(m, n, w) stream_append_hex_u64_width(&(m)->stream, (n), (w)) 1054 1055 #define MATLAB_NAMESPACE "OGL" 1056 1057 #define meta_begin_matlab_class_cracker(_1, _2, FN, ...) FN 1058 #define meta_begin_matlab_class_1(m, name) meta_begin_scope(m, str8("classdef " name)) 1059 #define meta_begin_matlab_class_2(m, name, type) \ 1060 meta_begin_scope(m, str8("classdef " name " < " type)) 1061 1062 #define meta_begin_matlab_class(m, ...) \ 1063 meta_begin_matlab_class_cracker(__VA_ARGS__, \ 1064 meta_begin_matlab_class_2, \ 1065 meta_begin_matlab_class_1)(m, __VA_ARGS__) 1066 1067 function b32 1068 meta_end_and_write_matlab(MetaprogramContext *m, char *path) 1069 { 1070 while (m->indentation_level > 0) meta_end_scope(m, str8("end")); 1071 b32 result = meta_write_and_reset(m, path); 1072 return result; 1073 } 1074 1075 #define META_ENTRY_KIND_LIST \ 1076 X(Invalid) \ 1077 X(Array) \ 1078 X(Bake) \ 1079 X(BeginScope) \ 1080 X(Constant) \ 1081 X(Embed) \ 1082 X(Emit) \ 1083 X(EndScope) \ 1084 X(Enumeration) \ 1085 X(Expand) \ 1086 X(Flags) \ 1087 X(FragmentShader) \ 1088 X(Library) \ 1089 X(MATLAB) \ 1090 X(PushConstants) \ 1091 X(RenderShader) \ 1092 X(Shader) \ 1093 X(ShaderAlias) \ 1094 X(ShaderGroup) \ 1095 X(String) \ 1096 X(Struct) \ 1097 X(Table) \ 1098 X(Union) \ 1099 X(VertexShader) \ 1100 1101 typedef enum { 1102 #define X(k, ...) MetaEntryKind_## k, 1103 META_ENTRY_KIND_LIST 1104 #undef X 1105 MetaEntryKind_Count, 1106 } MetaEntryKind; 1107 1108 #define X(k, ...) #k, 1109 read_only char *meta_entry_kind_strings[] = {META_ENTRY_KIND_LIST}; 1110 #undef X 1111 1112 #define META_EMIT_LANG_LIST \ 1113 X(C) \ 1114 X(CLibrary) \ 1115 X(MATLAB) 1116 1117 typedef enum { 1118 #define X(k, ...) MetaEmitLang_## k, 1119 META_EMIT_LANG_LIST 1120 #undef X 1121 MetaEmitLang_Count, 1122 } MetaEmitLang; 1123 1124 read_only u8 meta_kind_elements[] = { 1125 #define X(_k, _c, _g, _b, _m, _by, elements, ...) elements, 1126 META_KIND_LIST 1127 #undef X 1128 }; 1129 1130 read_only str8 meta_kind_meta_types[] = { 1131 #define X(k, ...) str8_comp(#k), 1132 META_KIND_LIST 1133 #undef X 1134 }; 1135 1136 read_only str8 meta_kind_matlab_types[] = { 1137 #define X(_k, _c, _g, _b, m, ...) str8_comp(#m), 1138 META_KIND_LIST 1139 #undef X 1140 }; 1141 1142 read_only str8 meta_kind_base_c_types[] = { 1143 #define X(_k, _c, _g, base, ...) str8_comp(#base), 1144 META_KIND_LIST 1145 #undef X 1146 }; 1147 1148 read_only str8 meta_kind_c_types[] = { 1149 #define X(_k, c, ...) str8_comp(#c), 1150 META_KIND_LIST 1151 #undef X 1152 }; 1153 1154 #define META_CURRENT_LOCATION (MetaLocation){__LINE__, 0} 1155 typedef struct { u32 line, column; } MetaLocation; 1156 1157 #define META_ENTRY_ARGUMENT_KIND_LIST \ 1158 X(None) \ 1159 X(String) \ 1160 X(Array) 1161 1162 #define X(k, ...) MetaEntryArgumentKind_## k, 1163 typedef enum {META_ENTRY_ARGUMENT_KIND_LIST} MetaEntryArgumentKind; 1164 #undef X 1165 1166 typedef struct { 1167 MetaEntryArgumentKind kind; 1168 MetaLocation location; 1169 union { 1170 str8 string; 1171 struct { 1172 str8 *strings; 1173 u64 count; 1174 }; 1175 }; 1176 } MetaEntryArgument; 1177 1178 typedef struct { 1179 MetaEntryKind kind; 1180 u32 argument_count; 1181 MetaEntryArgument *arguments; 1182 str8 name; 1183 MetaLocation location; 1184 } MetaEntry; 1185 1186 typedef struct { 1187 MetaEntry *data; 1188 da_count count; 1189 da_count capacity; 1190 str8 raw; 1191 } MetaEntryStack; 1192 1193 #define META_PARSE_TOKEN_LIST \ 1194 X('@', Entry) \ 1195 X('`', RawString) \ 1196 X('(', BeginArgs) \ 1197 X(')', EndArgs) \ 1198 X('[', BeginArray) \ 1199 X(']', EndArray) \ 1200 X('{', BeginScope) \ 1201 X('}', EndScope) 1202 1203 typedef enum { 1204 MetaParseToken_EOF, 1205 MetaParseToken_String, 1206 #define X(__1, kind, ...) MetaParseToken_## kind, 1207 META_PARSE_TOKEN_LIST 1208 #undef X 1209 MetaParseToken_Count, 1210 } MetaParseToken; 1211 1212 typedef union { 1213 MetaEntryKind kind; 1214 str8 string; 1215 } MetaParseUnion; 1216 1217 typedef struct { 1218 str8 s; 1219 MetaLocation location; 1220 } MetaParsePoint; 1221 1222 typedef struct { 1223 MetaParsePoint p; 1224 MetaParseUnion u; 1225 MetaParsePoint save_point; 1226 } MetaParser; 1227 1228 global char *compiler_file; 1229 global jmp_buf compiler_jmp_buf; 1230 1231 #define meta_parser_save(v) (v)->save_point = (v)->p 1232 #define meta_parser_restore(v) swap((v)->p, (v)->save_point) 1233 #define meta_parser_commit(v) meta_parser_restore(v) 1234 1235 #define meta_compiler_message(format, ...) \ 1236 fprintf(stderr, format, ##__VA_ARGS__) 1237 1238 #define meta_compiler_error_message(loc, format, ...) \ 1239 fprintf(stderr, "%s:%u:%u: error: "format, compiler_file, \ 1240 loc.line + 1, loc.column + 1, ##__VA_ARGS__) 1241 1242 #define meta_compiler_error(loc, format, ...) do { \ 1243 meta_compiler_error_message(loc, format, ##__VA_ARGS__); \ 1244 meta_error(); \ 1245 } while (0) 1246 1247 #define meta_entry_error(e, ...) meta_entry_error_column((e), (i32)(e)->location.column, __VA_ARGS__) 1248 #define meta_entry_error_column(e, column, ...) do { \ 1249 meta_compiler_error_message((e)->location, __VA_ARGS__); \ 1250 meta_entry_print((e), 2 * (column), 0); \ 1251 meta_error(); \ 1252 } while(0) 1253 1254 #define meta_entry_pair_error(e, prefix, base_kind) \ 1255 meta_entry_error(e, prefix"@%s() in @%s()\n", \ 1256 meta_entry_kind_strings[(e)->kind], \ 1257 meta_entry_kind_strings[(base_kind)]) 1258 1259 #define meta_entry_nesting_error(e, base_kind) meta_entry_pair_error(e, "invalid nesting: ", base_kind) 1260 1261 #define meta_entry_error_location(e, loc, ...) do { \ 1262 meta_compiler_error_message((loc), __VA_ARGS__); \ 1263 meta_entry_print((e), 1, (i32)(loc).column); \ 1264 meta_error(); \ 1265 } while (0) 1266 1267 function no_return void 1268 meta_error(void) 1269 { 1270 assert(0); 1271 longjmp(compiler_jmp_buf, 1); 1272 } 1273 1274 function void 1275 meta_entry_print(MetaEntry *e, i32 indent, i32 caret) 1276 { 1277 const char *kind = meta_entry_kind_strings[e->kind]; 1278 if (e->kind == MetaEntryKind_BeginScope) kind = "{"; 1279 if (e->kind == MetaEntryKind_EndScope) kind = "}"; 1280 1281 fprintf(stderr, "%*s@%s", indent, "", kind); 1282 1283 if (e->argument_count) { 1284 fprintf(stderr, "("); 1285 for (u32 i = 0; i < e->argument_count; i++) { 1286 MetaEntryArgument *a = e->arguments + i; 1287 if (i != 0) fprintf(stderr, " "); 1288 if (a->kind == MetaEntryArgumentKind_Array) { 1289 fprintf(stderr, "["); 1290 for (u64 j = 0; j < a->count; j++) { 1291 if (j != 0) fprintf(stderr, " "); 1292 fprintf(stderr, "%.*s", (i32)a->strings[j].length, a->strings[j].data); 1293 } 1294 fprintf(stderr, "]"); 1295 } else { 1296 fprintf(stderr, "%.*s", (i32)a->string.length, a->string.data); 1297 } 1298 } 1299 fprintf(stderr, ")"); 1300 } 1301 if (e->name.length) fprintf(stderr, " %.*s", (i32)e->name.length, e->name.data); 1302 1303 if (caret >= 0) fprintf(stderr, "\n%*s^", indent + caret, ""); 1304 1305 fprintf(stderr, "\n"); 1306 } 1307 1308 function i64 1309 meta_lookup_string_slow(const str8 *strings, i64 string_count, str8 s) 1310 { 1311 // TODO(rnp): obviously this is slow 1312 i64 result = -1; 1313 for (i64 i = 0; i < string_count; i++) { 1314 if (str8_equal(s, strings[i])) { 1315 result = i; 1316 break; 1317 } 1318 } 1319 return result; 1320 } 1321 1322 function MetaEntryKind 1323 meta_entry_kind_from_string(str8 s) 1324 { 1325 #define X(k, ...) str8_comp(#k), 1326 read_only str8 kinds[] = {META_ENTRY_KIND_LIST}; 1327 #undef X 1328 MetaEntryKind result = MetaEntryKind_Invalid; 1329 i64 id = meta_lookup_string_slow(kinds + 1, countof(kinds) - 1, s); 1330 if (id > 0) result = (MetaEntryKind)(id + 1); 1331 return result; 1332 } 1333 1334 function void 1335 meta_parser_trim(MetaParser *p) 1336 { 1337 u8 *s, *end = p->p.s.data + p->p.s.length; 1338 b32 done = 0; 1339 b32 comment = 0; 1340 for (s = p->p.s.data; !done && s != end;) { 1341 switch (*s) { 1342 case '\r': case '\t': case ' ': 1343 { 1344 p->p.location.column++; 1345 }break; 1346 case '\n':{ p->p.location.line++; p->p.location.column = 0; comment = 0; }break; 1347 case '/':{ 1348 comment |= ((s + 1) != end && s[1] == '/'); 1349 if (comment) s++; 1350 } /* FALLTHROUGH */ 1351 default:{done = !comment;}break; 1352 } 1353 if (!done) s++; 1354 } 1355 p->p.s.data = s; 1356 p->p.s.length = end - s; 1357 } 1358 1359 function str8 1360 meta_parser_extract_raw_string(MetaParser *p) 1361 { 1362 str8 result = {.data = p->p.s.data}; 1363 for (; result.length < p->p.s.length; result.length++) { 1364 u8 byte = p->p.s.data[result.length]; 1365 p->p.location.column++; 1366 if (byte == '`') { 1367 break; 1368 } else if (byte == '\n') { 1369 p->p.location.column = 0; 1370 p->p.location.line++; 1371 } 1372 } 1373 p->p.s.data += (result.length + 1); 1374 p->p.s.length -= (result.length + 1); 1375 return result; 1376 } 1377 1378 function str8 1379 meta_parser_extract_string(MetaParser *p) 1380 { 1381 str8 result = {.data = p->p.s.data}; 1382 for (; result.length < p->p.s.length; result.length++) { 1383 b32 done = 0; 1384 switch (p->p.s.data[result.length]) { 1385 #define X(t, ...) case t: 1386 META_PARSE_TOKEN_LIST 1387 #undef X 1388 case ' ': case '\n': case '\r': case '\t': 1389 {done = 1;}break; 1390 case '/':{ 1391 done = (result.length + 1 < p->p.s.length) && (p->p.s.data[result.length + 1] == '/'); 1392 }break; 1393 default:{}break; 1394 } 1395 if (done) break; 1396 } 1397 p->p.location.column += (u32)result.length; 1398 p->p.s.data += result.length; 1399 p->p.s.length -= result.length; 1400 return result; 1401 } 1402 1403 function str8 1404 meta_parser_token_name(MetaParser *p, MetaParseToken t) 1405 { 1406 str8 result = str8("\"invalid\""); 1407 read_only str8 names[MetaParseToken_Count] = { 1408 [MetaParseToken_EOF] = str8_comp("\"EOF\""), 1409 #define X(k, v, ...) [MetaParseToken_## v] = str8_comp(#k), 1410 META_PARSE_TOKEN_LIST 1411 #undef X 1412 }; 1413 if (t >= 0 && t < countof(names)) result = names[t]; 1414 if (t == MetaParseToken_String) result = p->u.string; 1415 if (t == MetaParseToken_RawString) result = (str8){.data = p->u.string.data - 1, .length = p->u.string.length + 1}; 1416 return result; 1417 } 1418 1419 function MetaParseToken 1420 meta_parser_token(MetaParser *p) 1421 { 1422 MetaParseToken result = MetaParseToken_EOF; 1423 meta_parser_save(p); 1424 if (p->p.s.length > 0) { 1425 b32 chop = 1; 1426 switch (p->p.s.data[0]) { 1427 #define X(t, kind, ...) case t:{ result = MetaParseToken_## kind; }break; 1428 META_PARSE_TOKEN_LIST 1429 #undef X 1430 default:{ result = MetaParseToken_String; chop = 0; }break; 1431 } 1432 if (chop) { str8_chop(&p->p.s, 1); p->p.location.column++; } 1433 1434 if (result != MetaParseToken_RawString) meta_parser_trim(p); 1435 switch (result) { 1436 case MetaParseToken_RawString:{ p->u.string = meta_parser_extract_raw_string(p); }break; 1437 case MetaParseToken_String:{ p->u.string = meta_parser_extract_string(p); }break; 1438 1439 /* NOTE(rnp): '{' and '}' are shorthand for @BeginScope and @EndScope */ 1440 case MetaParseToken_BeginScope:{ p->u.kind = MetaEntryKind_BeginScope; }break; 1441 case MetaParseToken_EndScope:{ p->u.kind = MetaEntryKind_EndScope; }break; 1442 1443 /* NOTE(rnp): loose '[' implies implicit @Array() */ 1444 case MetaParseToken_BeginArray:{ p->u.kind = MetaEntryKind_Array; }break; 1445 1446 case MetaParseToken_Entry:{ 1447 str8 kind = meta_parser_extract_string(p); 1448 p->u.kind = meta_entry_kind_from_string(kind); 1449 if (p->u.kind == MetaEntryKind_Invalid) { 1450 meta_compiler_error(p->p.location, "invalid keyword: @%.*s\n", (i32)kind.length, kind.data); 1451 } 1452 }break; 1453 default:{}break; 1454 } 1455 meta_parser_trim(p); 1456 } 1457 1458 return result; 1459 } 1460 1461 function MetaParseToken 1462 meta_parser_peek_token(MetaParser *p) 1463 { 1464 MetaParseToken result = meta_parser_token(p); 1465 meta_parser_restore(p); 1466 return result; 1467 } 1468 1469 function void 1470 meta_parser_unexpected_token(MetaParser *p, MetaParseToken t) 1471 { 1472 meta_parser_restore(p); 1473 str8 token_name = meta_parser_token_name(p, t); 1474 meta_compiler_error(p->p.location, "unexpected token: %.*s\n", (i32)token_name.length, token_name.data); 1475 } 1476 1477 function void 1478 meta_parser_fill_argument_array(MetaParser *p, MetaEntryArgument *array, Arena *arena) 1479 { 1480 str8_list strings = {0}; 1481 array->kind = MetaEntryArgumentKind_Array; 1482 array->location = p->p.location; 1483 for (MetaParseToken token = meta_parser_token(p); 1484 token != MetaParseToken_EndArray; 1485 token = meta_parser_token(p)) 1486 { 1487 switch (token) { 1488 case MetaParseToken_RawString: 1489 case MetaParseToken_String: 1490 { 1491 *da_push(arena, &strings) = p->u.string; 1492 }break; 1493 default:{ meta_parser_unexpected_token(p, token); }break; 1494 } 1495 } 1496 array->strings = strings.data; 1497 array->count = strings.count; 1498 arena_pop(arena, (strings.capacity - strings.count) * sizeof(*strings.data)); 1499 } 1500 1501 function void 1502 meta_parser_arguments(MetaParser *p, MetaEntry *e, Arena *arena) 1503 { 1504 if (meta_parser_peek_token(p) == MetaParseToken_BeginArgs) { 1505 meta_parser_commit(p); 1506 1507 struct { 1508 MetaEntryArgument *data; 1509 da_count count; 1510 da_count capacity; 1511 } arguments = {0}; 1512 1513 for (MetaParseToken token = meta_parser_token(p); 1514 token != MetaParseToken_EndArgs; 1515 token = meta_parser_token(p)) 1516 { 1517 MetaEntryArgument *arg = da_push(arena, &arguments); 1518 switch (token) { 1519 case MetaParseToken_RawString: 1520 case MetaParseToken_String: 1521 { 1522 arg->kind = MetaEntryArgumentKind_String; 1523 arg->string = p->u.string; 1524 arg->location = p->p.location; 1525 }break; 1526 case MetaParseToken_BeginArray:{ 1527 meta_parser_fill_argument_array(p, arg, arena); 1528 }break; 1529 default:{ meta_parser_unexpected_token(p, token); }break; 1530 } 1531 } 1532 e->arguments = arguments.data; 1533 e->argument_count = arguments.count; 1534 // TODO(rnp): we should count arguments first so that we don't need to leave a hole 1535 //arena_pop(arena, (arguments.capacity - arguments.count) * sizeof(*arguments.data)); 1536 } 1537 } 1538 1539 typedef struct { 1540 MetaEntry *start; 1541 MetaEntry *one_past_last; 1542 i64 consumed; 1543 } MetaEntryScope; 1544 1545 function MetaEntryScope 1546 meta_entry_extract_scope(MetaEntry *base, i64 entry_count) 1547 { 1548 assert(base->kind != MetaEntryKind_BeginScope && base->kind != MetaEntryKind_EndScope); 1549 assert(entry_count > 0); 1550 1551 MetaEntryScope result = {.start = base + 1, .consumed = 1}; 1552 i64 sub_scope = 0; 1553 for (MetaEntry *e = result.start; result.consumed < entry_count; result.consumed++, e++) { 1554 switch (e->kind) { 1555 case MetaEntryKind_BeginScope:{ sub_scope++; }break; 1556 case MetaEntryKind_EndScope:{ sub_scope--; }break; 1557 default:{}break; 1558 } 1559 if (sub_scope == 0) break; 1560 } 1561 1562 if (sub_scope != 0) 1563 meta_entry_error(base, "unclosed scope for entry\n"); 1564 1565 result.one_past_last = base + result.consumed; 1566 if (result.start->kind == MetaEntryKind_BeginScope) result.start++; 1567 if (result.one_past_last == result.start) result.one_past_last++; 1568 1569 return result; 1570 } 1571 1572 function MetaEntryStack 1573 meta_entry_stack_from_file(Arena *arena, char *file) 1574 { 1575 MetaParser parser = {.p.s = os_read_entire_file(arena, file)}; 1576 MetaEntryStack result = {.raw = parser.p.s}; 1577 1578 compiler_file = file; 1579 1580 meta_parser_trim(&parser); 1581 1582 for (MetaParseToken token = meta_parser_token(&parser); 1583 token != MetaParseToken_EOF; 1584 token = meta_parser_token(&parser)) 1585 { 1586 MetaEntry *e = da_push(arena, &result); 1587 switch (token) { 1588 case MetaParseToken_String: 1589 case MetaParseToken_RawString: 1590 { 1591 e->kind = MetaEntryKind_String; 1592 e->location = parser.save_point.location; 1593 e->name = parser.u.string; 1594 }break; 1595 1596 case MetaParseToken_BeginScope: 1597 case MetaParseToken_EndScope: 1598 { 1599 e->kind = parser.u.kind; 1600 e->location = parser.save_point.location; 1601 }break; 1602 1603 case MetaParseToken_BeginArray: 1604 case MetaParseToken_Entry: 1605 { 1606 e->kind = parser.u.kind; 1607 e->location = parser.save_point.location; 1608 1609 if (token == MetaParseToken_Entry) 1610 meta_parser_arguments(&parser, e, arena); 1611 1612 if (token == MetaParseToken_BeginArray) { 1613 MetaEntryArgument *a = e->arguments = push_struct(arena, MetaEntryArgument); 1614 e->argument_count = 1; 1615 meta_parser_fill_argument_array(&parser, a, arena); 1616 } 1617 1618 if (meta_parser_peek_token(&parser) == MetaParseToken_String) { 1619 meta_parser_commit(&parser); 1620 e->name = parser.u.string; 1621 } 1622 }break; 1623 1624 default:{ meta_parser_unexpected_token(&parser, token); }break; 1625 } 1626 } 1627 1628 return result; 1629 } 1630 1631 #define meta_entry_argument_expected(e, ...) \ 1632 meta_entry_argument_expected_((e), arg_list(str8, __VA_ARGS__)) 1633 function void 1634 meta_entry_argument_expected_(MetaEntry *e, str8 *args, u64 count) 1635 { 1636 if (e->argument_count != count) { 1637 meta_compiler_error_message(e->location, "incorrect argument count for entry %s() got: %u expected: %u\n", 1638 meta_entry_kind_strings[e->kind], e->argument_count, (u32)count); 1639 fprintf(stderr, " format: @%s(", meta_entry_kind_strings[e->kind]); 1640 for EachIndex(count, it) { 1641 if (it != 0) fprintf(stderr, ", "); 1642 fprintf(stderr, "%.*s", (i32)args[it].length, args[it].data); 1643 } 1644 fprintf(stderr, ")\n"); 1645 meta_error(); 1646 } 1647 } 1648 1649 function MetaEntryArgument 1650 meta_entry_argument_expect(MetaEntry *e, u32 index, MetaEntryArgumentKind kind) 1651 { 1652 #define X(k, ...) #k, 1653 read_only char *kinds[] = {META_ENTRY_ARGUMENT_KIND_LIST}; 1654 #undef X 1655 1656 assert(e->argument_count > index); 1657 MetaEntryArgument result = e->arguments[index]; 1658 1659 if (result.kind != kind) { 1660 meta_entry_error_location(e, result.location, "unexpected argument kind: expected %s but got: %s\n", 1661 kinds[kind], kinds[result.kind]); 1662 } 1663 1664 if (kind == MetaEntryArgumentKind_Array && result.count == 0) 1665 meta_entry_error_location(e, result.location, "array arguments must have at least 1 element\n"); 1666 1667 return result; 1668 } 1669 1670 typedef struct { da_count value; } MetaEntityID; 1671 1672 typedef struct { 1673 da_count *data; 1674 da_count count; 1675 da_count capacity; 1676 } MetaIDList; 1677 1678 typedef enum { 1679 MetaExpansionPartKind_Alignment, 1680 MetaExpansionPartKind_Conditional, 1681 MetaExpansionPartKind_EvalKind, 1682 MetaExpansionPartKind_EvalKindCount, 1683 MetaExpansionPartKind_Reference, 1684 MetaExpansionPartKind_String, 1685 } MetaExpansionPartKind; 1686 1687 typedef enum { 1688 MetaExpansionConditionalArgumentKind_Invalid, 1689 MetaExpansionConditionalArgumentKind_Number, 1690 MetaExpansionConditionalArgumentKind_Evaluation, 1691 MetaExpansionConditionalArgumentKind_Reference, 1692 } MetaExpansionConditionalArgumentKind; 1693 1694 typedef struct { 1695 MetaExpansionConditionalArgumentKind kind; 1696 union { 1697 str8 *strings; 1698 i64 number; 1699 }; 1700 } MetaExpansionConditionalArgument; 1701 1702 typedef enum { 1703 MetaExpansionOperation_Invalid, 1704 MetaExpansionOperation_LessThan, 1705 MetaExpansionOperation_GreaterThan, 1706 } MetaExpansionOperation; 1707 1708 typedef struct { 1709 MetaExpansionConditionalArgument lhs; 1710 MetaExpansionConditionalArgument rhs; 1711 MetaExpansionOperation op; 1712 u32 instruction_skip; 1713 } MetaExpansionConditional; 1714 1715 typedef struct { 1716 MetaExpansionPartKind kind; 1717 union { 1718 str8 string; 1719 str8 *strings; 1720 MetaExpansionConditional conditional; 1721 }; 1722 } MetaExpansionPart; 1723 DA_STRUCT(MetaExpansionPart, MetaExpansionPart); 1724 1725 typedef enum { 1726 MetaEmitOperationKind_Expand, 1727 MetaEmitOperationKind_FileBytes, 1728 MetaEmitOperationKind_String, 1729 } MetaEmitOperationKind; 1730 1731 typedef struct { 1732 MetaExpansionPart *parts; 1733 u32 part_count; 1734 da_count table_entity_id; 1735 } MetaEmitOperationExpansion; 1736 1737 typedef struct { 1738 union { 1739 str8 string; 1740 MetaEmitOperationExpansion expansion_operation; 1741 }; 1742 MetaEmitOperationKind kind; 1743 MetaLocation location; 1744 } MetaEmitOperation; 1745 1746 typedef struct { 1747 MetaEmitOperation *data; 1748 da_count count; 1749 da_count capacity; 1750 1751 str8 filename; 1752 } MetaEmitOperationList; 1753 1754 typedef struct { 1755 MetaEmitOperationList *data; 1756 da_count count; 1757 da_count capacity; 1758 } MetaEmitOperationListSet; 1759 1760 typedef enum { 1761 MetaShaderKind_Alias, 1762 MetaShaderKind_Compute, 1763 MetaShaderKind_Render, 1764 MetaShaderKind_Count, 1765 } MetaShaderKind; 1766 1767 typedef enum { 1768 MetaShaderPrimitiveKind_Mesh, 1769 MetaShaderPrimitiveKind_Vertex, 1770 MetaShaderPrimitiveKind_Count, 1771 } MetaShaderPrimitiveKind; 1772 1773 typedef struct { 1774 MetaShaderPrimitiveKind kind; 1775 } MetaRenderShader; 1776 1777 typedef struct { 1778 MetaShaderKind kind; 1779 MetaIDList entity_reference_ids; 1780 str8 files[2]; 1781 union { 1782 MetaEntityID alias_parent_id; 1783 MetaRenderShader render; 1784 }; 1785 } MetaShader; 1786 1787 #define META_STRUCT_FIELDS \ 1788 X(Name, name) \ 1789 X(Type, type) \ 1790 X(Elements, elements) \ 1791 1792 #define X(id, ...) MetaStructField_##id, 1793 typedef enum {META_STRUCT_FIELDS} MetaStructFields; 1794 #undef X 1795 1796 typedef struct { 1797 str8 *fields; 1798 str8 **entries; 1799 u32 field_count; 1800 u32 entry_count; 1801 union { 1802 i32 struct_info_id; 1803 }; 1804 } MetaTable; 1805 1806 typedef enum { 1807 MetaConstantKind_Integer, 1808 MetaConstantKind_Float, 1809 MetaConstantKind_Count, 1810 } MetaConstantKind; 1811 1812 typedef struct { 1813 MetaConstantKind kind; 1814 u32 name_id; 1815 union { 1816 u64 U64; 1817 f64 F64; 1818 }; 1819 } MetaConstant; 1820 1821 typedef struct { 1822 str8 reference_name; 1823 MetaEntityID resolved_id; 1824 da_count reference_count; 1825 1826 // NOTE: only used for namespacing MATLAB unions 1827 str8 scope_name; 1828 } MetaEntityReference; 1829 1830 // X(name, is_table, is_struct, struct_reference_target) 1831 #define META_ENTITY_KIND_LIST \ 1832 X(Nil, 0, 0, 0) \ 1833 X(List, 0, 0, 0) \ 1834 X(BakeParameters, 1, 1, 0) \ 1835 X(Constant, 0, 0, 0) \ 1836 X(Enumeration, 1, 0, 1) \ 1837 X(Flags, 1, 0, 1) \ 1838 X(PushConstants, 1, 1, 0) \ 1839 X(Reference, 0, 0, 0) \ 1840 X(ReferenceReference, 0, 0, 0) \ 1841 X(Shader, 0, 0, 0) \ 1842 X(ShaderGroup, 0, 0, 0) \ 1843 X(Struct, 1, 1, 1) \ 1844 X(Table, 1, 0, 0) \ 1845 X(Union, 1, 1, 1) \ 1846 1847 // X(EntityKind, AllowReferences, Emit) 1848 #define META_STRUCT_MAP_LIST \ 1849 X(BakeParameters, 0, 1) \ 1850 X(PushConstants, 0, 1) \ 1851 X(Struct, 1, 1) \ 1852 X(Union, 1, 0) \ 1853 1854 1855 typedef enum { 1856 #define X(name, ...) MetaEntityKind_ ##name, 1857 META_ENTITY_KIND_LIST 1858 #undef X 1859 MetaEntityKind_Count, 1860 } MetaEntityKind; 1861 1862 typedef struct { 1863 MetaEntityKind kind; 1864 MetaEntityID parent; 1865 MetaEntityID first_child; 1866 MetaEntityID next_sibling; 1867 MetaEntityID previous_sibling; 1868 MetaLocation location; 1869 union { 1870 MetaConstant constant; 1871 MetaEntityReference reference; 1872 MetaShader shader; 1873 MetaTable table; 1874 }; 1875 } MetaEntity; 1876 DA_STRUCT(MetaEntity, MetaEntity); 1877 1878 #define X(name, ...) str8_comp(#name), 1879 read_only str8 meta_entity_kind_names[] = {META_ENTITY_KIND_LIST}; 1880 #undef X 1881 #define X(_n, table, ...) table, 1882 read_only b8 meta_entity_kind_is_table[] = {META_ENTITY_KIND_LIST}; 1883 #undef X 1884 #define X(_n, _t, s, ...) s, 1885 read_only b8 meta_entity_kind_is_struct[] = {META_ENTITY_KIND_LIST}; 1886 #undef X 1887 #define X(_n, _t, _s, srt, ...) srt, 1888 read_only b8 meta_entity_kind_struct_reference_target[] = {META_ENTITY_KIND_LIST}; 1889 #undef X 1890 1891 #define X(k, ...) MetaEntityKind_##k, 1892 read_only MetaEntityKind meta_struct_entity_kinds[] = {META_STRUCT_MAP_LIST}; 1893 #undef X 1894 #define X(_k, allow, ...) allow, 1895 read_only b8 meta_struct_allow_references[] = {META_STRUCT_MAP_LIST}; 1896 #undef X 1897 #define X(_k, _a, emit, ...) emit, 1898 read_only b8 meta_struct_emit[] = {META_STRUCT_MAP_LIST}; 1899 #undef X 1900 1901 typedef enum { 1902 MetaBuildStructMemberFlag_ReferenceType = 1 << 0, 1903 MetaBuildStructMemberFlag_ReferenceElements = 1 << 1, 1904 MetaBuildStructMemberFlag_EnumerationCount = 1 << 2, 1905 } MetaBuildStructMemberFlags; 1906 1907 typedef struct { 1908 MetaStructInfo info; 1909 1910 str8 *members; 1911 i32 *type_ids; 1912 i32 *elements; 1913 1914 MetaBuildStructMemberFlags *member_flags; 1915 1916 MetaEntityID entity; 1917 MetaLocation location; 1918 } MetaStruct; 1919 1920 typedef struct { 1921 Arena *arena, *scratch; 1922 1923 str8 filename; 1924 str8 directory; 1925 str8 fullpath; 1926 1927 MetaEntityID library_entity; 1928 MetaEntityID matlab_entity; 1929 1930 // NOTE(rnp): arrays of entity ids sorted by kind and counted by entity_kind_counts 1931 da_count *entity_kind_ids[MetaEntityKind_Count]; 1932 1933 da_count entity_kind_counts[MetaEntityKind_Count]; 1934 str8_list entity_names; 1935 MetaEntityList entities; 1936 1937 // NOTE(rnp): list of all entities referenced by shaders. needed for header string baking 1938 MetaIDList shader_entity_references; 1939 1940 // NOTE(rnp): fully resolved structs 1941 MetaStruct *struct_infos; 1942 u32 struct_infos_count; 1943 1944 // NOTE(rnp): dumb jank to support treating CudaHilbert/CudaDecode as shaders and 1945 // allowing shader names to alias. 1946 da_count base_shader_count; 1947 da_count *base_shader_ids; 1948 // NOTE(rnp): map index in the entity_kind_ids[MetaEntityKind_Shader] to base_shader_ids index 1949 da_count *base_shader_id_map; 1950 1951 1952 MetaEmitOperationListSet emit_sets[MetaEmitLang_Count]; 1953 } MetaContext; 1954 1955 function da_count 1956 meta_lookup_id_slow(da_count *v, da_count count, da_count id) 1957 { 1958 // TODO(rnp): obviously this is slow 1959 da_count result = -1; 1960 for (da_count i = 0; i < count; i++) { 1961 if (id == v[i]) { 1962 result = i; 1963 break; 1964 } 1965 } 1966 return result; 1967 } 1968 1969 function da_count 1970 meta_intern_string(MetaContext *ctx, str8_list *sv, str8 s) 1971 { 1972 da_count result = meta_lookup_string_slow(sv->data, sv->count, s); 1973 if (result < 0) { 1974 *da_push(ctx->arena, sv) = s; 1975 result = sv->count - 1; 1976 } 1977 return result; 1978 } 1979 1980 function da_count 1981 meta_intern_id(MetaContext *ctx, MetaIDList *v, da_count id) 1982 { 1983 da_count result = meta_lookup_id_slow(v->data, v->count, id); 1984 if (result < 0) { 1985 *da_push(ctx->arena, v) = id; 1986 result = v->count - 1; 1987 } 1988 return result; 1989 } 1990 1991 function da_count 1992 meta_entity_children_count(MetaContext *ctx, MetaEntityID entity_id) 1993 { 1994 MetaEntityID child = ctx->entities.data[entity_id.value].first_child; 1995 da_count result = 0; 1996 if (child.value != 0) { 1997 do { 1998 result++; 1999 child = ctx->entities.data[child.value].next_sibling; 2000 } while (child.value != ctx->entities.data[entity_id.value].first_child.value); 2001 } 2002 return result; 2003 } 2004 2005 function da_count * 2006 meta_entity_extract_children(MetaContext *ctx, MetaEntityID entity_id, da_count *children_count, Arena *arena) 2007 { 2008 *children_count = meta_entity_children_count(ctx, entity_id); 2009 da_count *result = push_array_no_zero(arena, da_count, *children_count); 2010 2011 // NOTE(rnp): children are pushed in LIFO order 2012 MetaEntity *e = ctx->entities.data + entity_id.value; 2013 da_count index = 0; 2014 MetaEntityID child = e->first_child; 2015 do { 2016 child = ctx->entities.data[child.value].previous_sibling; 2017 result[index++] = child.value; 2018 } while (child.value != e->first_child.value); 2019 2020 return result; 2021 } 2022 2023 function MetaEntity * 2024 meta_entity(MetaContext *ctx, MetaEntityID id) 2025 { 2026 assert(id.value != 0 && id.value < ctx->entities.count); 2027 MetaEntity *result = ctx->entities.data + id.value; 2028 return result; 2029 } 2030 2031 function MetaEntityID 2032 meta_root_entity_id(MetaContext *ctx) 2033 { 2034 MetaEntityID result = {0}; 2035 return result; 2036 } 2037 2038 function MetaEntityID 2039 meta_intern_entity(MetaContext *ctx, str8 name, MetaEntityKind kind, MetaEntityID parent, 2040 MetaLocation location, b32 allow_existing) 2041 { 2042 MetaEntityID result = {0}; 2043 assert(ctx->entities.data[0].kind == MetaEntityKind_Nil); 2044 assert(Between(kind, MetaEntityKind_Nil + 1, MetaEntityKind_Count - 1)); 2045 2046 da_count name_id = meta_intern_string(ctx, &ctx->entity_names, name); 2047 if (name_id < ctx->entities.count && ctx->entities.data[name_id].kind != kind) { 2048 str8 old_kind = meta_entity_kind_names[ctx->entities.data[name_id].kind]; 2049 str8 new_kind = meta_entity_kind_names[kind]; 2050 meta_compiler_error_message(location, "attempting to redefine %.*s as kind %.*s\n", 2051 (i32)name.length, name.data, (i32)new_kind.length, new_kind.data); 2052 meta_compiler_error_message(ctx->entities.data[name_id].location, "previously defined as kind %.*s\n", 2053 (i32)old_kind.length, old_kind.data); 2054 meta_error(); 2055 } else if (name_id < ctx->entities.count && !allow_existing) { 2056 meta_compiler_error_message(location, "redefinition of %.*s\n", (i32)name.length, name.data); 2057 meta_compiler_error_message(ctx->entities.data[name_id].location, "previously defined here\n"); 2058 meta_error(); 2059 } else { 2060 if (name_id < ctx->entities.count) { 2061 result.value = name_id; 2062 } else { 2063 ctx->entity_kind_counts[kind]++; 2064 MetaEntity *new = da_push(ctx->arena, &ctx->entities); 2065 new->location = location; 2066 result.value = da_index(new, &ctx->entities); 2067 } 2068 2069 MetaEntity *e = ctx->entities.data + result.value; 2070 e->kind = kind; 2071 e->parent = parent; 2072 2073 MetaEntity *p = ctx->entities.data + parent.value; 2074 e->next_sibling = p->first_child; 2075 p->first_child = result; 2076 2077 if (e->next_sibling.value == 0) 2078 e->next_sibling = p->first_child; 2079 2080 e->previous_sibling = ctx->entities.data[e->next_sibling.value].previous_sibling; 2081 ctx->entities.data[e->next_sibling.value].previous_sibling = result; 2082 ctx->entities.data[e->previous_sibling.value].next_sibling = result; 2083 } 2084 2085 return result; 2086 } 2087 2088 function MetaEntityID 2089 meta_entity_reference(MetaContext *ctx, str8 name, MetaLocation location) 2090 { 2091 MetaEntityID result = {0}; 2092 Temp scratch; 2093 DeferLoop(scratch = temp_begin(ctx->scratch), temp_end(scratch)) { 2094 str8 ref_name = push_str8_from_parts(ctx->scratch, str8(""), str8("R"), name); 2095 result = meta_intern_entity(ctx, ref_name, MetaEntityKind_Reference, 2096 meta_root_entity_id(ctx), location, 1); 2097 MetaEntity *r = meta_entity(ctx, result); 2098 if (r->reference.reference_count == 0) 2099 ctx->entity_names.data[result.value] = push_str8(ctx->arena, ref_name); 2100 r->reference.reference_count++; 2101 r->reference.reference_name = name; 2102 } 2103 return result; 2104 } 2105 2106 function MetaEntityID 2107 meta_entity_reference_reference(MetaContext *ctx, str8 name, str8 scope_name, MetaLocation location, 2108 MetaEntityID parent, str8 prefix) 2109 { 2110 MetaEntityID result = {0}; 2111 // NOTE(rnp): base reference 2112 MetaEntityID ref_id = meta_entity_reference(ctx, name, location); 2113 2114 Temp scratch; 2115 DeferLoop(scratch = temp_begin(ctx->scratch), temp_end(scratch)) { 2116 str8 refref_name = push_str8_from_parts(ctx->scratch, str8(""), prefix, str8("RR"), name); 2117 result = meta_intern_entity(ctx, refref_name, MetaEntityKind_ReferenceReference, 2118 parent, location, 1); 2119 2120 MetaEntity *rr = meta_entity(ctx, result); 2121 if (rr->reference.reference_count == 0) 2122 ctx->entity_names.data[result.value] = push_str8(ctx->arena, refref_name); 2123 rr->reference.reference_count++; 2124 rr->reference.reference_name = name; 2125 rr->reference.resolved_id = ref_id; 2126 rr->reference.scope_name = scope_name; 2127 } 2128 return result; 2129 } 2130 2131 function MetaEntityID 2132 meta_entity_first_child_of_kind(MetaContext *ctx, MetaEntity *e, MetaEntityKind kind) 2133 { 2134 MetaEntityID result = {0}; 2135 MetaEntityID child = e->first_child; 2136 if (child.value) do { 2137 if (ctx->entities.data[child.value].kind == kind) { 2138 result = child; 2139 break; 2140 } 2141 child = ctx->entities.data[child.value].next_sibling; 2142 } while (child.value != e->first_child.value); 2143 return result; 2144 } 2145 2146 function void 2147 meta_expansion_string_split(str8 string, str8 *left, str8 *inner, str8 *remainder, MetaLocation loc) 2148 { 2149 b32 found = 0; 2150 for (u8 *s = string.data, *e = s + string.length; (s + 1) != e; s++) { 2151 u32 val = (u32)'$' << 8u | (u32)'('; 2152 u32 test = (u32)s[0] << 8u | s[1]; 2153 if (test == val) { 2154 if (left) { 2155 left->data = string.data; 2156 left->length = s - string.data; 2157 } 2158 2159 u8 *start = s + 2; 2160 while (s != e && *s != ')') s++; 2161 if (s == e) { 2162 meta_compiler_error_message(loc, "unterminated expansion in raw string:\n %.*s\n", 2163 (i32)string.length, string.data); 2164 fprintf(stderr, " %.*s^\n", (i32)(start - string.data), ""); 2165 meta_error(); 2166 } 2167 2168 if (inner) { 2169 inner->data = start; 2170 inner->length = s - start; 2171 } 2172 2173 if (remainder) { 2174 remainder->data = s + 1; 2175 remainder->length = string.length - (remainder->data - string.data); 2176 } 2177 found = 1; 2178 break; 2179 } 2180 } 2181 if (!found) { 2182 if (left) *left = string; 2183 if (inner) *inner = (str8){0}; 2184 if (remainder) *remainder = (str8){0}; 2185 } 2186 } 2187 2188 function MetaExpansionPart * 2189 meta_push_expansion_part(MetaContext *ctx, Arena *arena, MetaExpansionPartList *parts, 2190 MetaExpansionPartKind kind, str8 string, MetaEntity *table, MetaLocation loc) 2191 { 2192 MetaExpansionPart *result = da_push(arena, parts); 2193 2194 result->kind = kind; 2195 switch (kind) { 2196 case MetaExpansionPartKind_Alignment: 2197 case MetaExpansionPartKind_Conditional: 2198 {}break; 2199 2200 case MetaExpansionPartKind_EvalKind: 2201 case MetaExpansionPartKind_EvalKindCount: 2202 case MetaExpansionPartKind_Reference: 2203 { 2204 assert(meta_entity_kind_is_table[table->kind]); 2205 MetaTable *t = &table->table; 2206 2207 da_count index = meta_lookup_string_slow(t->fields, t->field_count, string); 2208 result->strings = t->entries[index]; 2209 if (index < 0) { 2210 /* TODO(rnp): fix this location to point directly at the field in the string */ 2211 str8 table_name = ctx->entity_names.data[da_index(table, &ctx->entities)]; 2212 meta_compiler_error(loc, "table \"%.*s\" does not contain member: %.*s\n", 2213 (i32)table_name.length, table_name.data, (i32)string.length, string.data); 2214 } 2215 }break; 2216 2217 case MetaExpansionPartKind_String:{ result->string = string; }break; 2218 InvalidDefaultCase; 2219 } 2220 return result; 2221 } 2222 2223 #define META_EXPANSION_TOKEN_LIST \ 2224 X('|', Alignment) \ 2225 X('%', TypeEval) \ 2226 X('#', TypeEvalElements) \ 2227 X('"', Quote) \ 2228 X('-', Dash) \ 2229 X('>', GreaterThan) \ 2230 X('<', LessThan) \ 2231 2232 typedef enum { 2233 MetaExpansionToken_EOF, 2234 MetaExpansionToken_Identifier, 2235 MetaExpansionToken_Number, 2236 MetaExpansionToken_String, 2237 #define X(__1, kind, ...) MetaExpansionToken_## kind, 2238 META_EXPANSION_TOKEN_LIST 2239 #undef X 2240 MetaExpansionToken_Count, 2241 } MetaExpansionToken; 2242 2243 read_only str8 meta_expansion_token_strings[] = { 2244 str8_comp("EOF"), 2245 str8_comp("Indentifier"), 2246 str8_comp("Number"), 2247 str8_comp("String"), 2248 #define X(s, kind, ...) str8_comp(#s), 2249 META_EXPANSION_TOKEN_LIST 2250 #undef X 2251 }; 2252 2253 typedef struct { 2254 str8 s; 2255 union { 2256 i64 number; 2257 str8 string; 2258 }; 2259 str8 save; 2260 MetaLocation loc; 2261 } MetaExpansionParser; 2262 2263 #define meta_expansion_save(v) (v)->save = (v)->s 2264 #define meta_expansion_restore(v) swap((v)->s, (v)->save) 2265 #define meta_expansion_commit(v) meta_expansion_restore(v) 2266 2267 #define meta_expansion_expected(loc, e, g) \ 2268 meta_compiler_error(loc, "invalid expansion string: expected %.*s after %.*s\n", \ 2269 (i32)meta_expansion_token_strings[e].length, meta_expansion_token_strings[e].data, \ 2270 (i32)meta_expansion_token_strings[g].length, meta_expansion_token_strings[g].data) 2271 2272 function str8 2273 meta_expansion_extract_string(MetaExpansionParser *p) 2274 { 2275 str8 result = {.data = p->s.data}; 2276 for (; result.length < p->s.length; result.length++) { 2277 b32 done = 0; 2278 switch (p->s.data[result.length]) { 2279 #define X(t, ...) case t: 2280 META_EXPANSION_TOKEN_LIST 2281 #undef X 2282 case ' ': 2283 {done = 1;}break; 2284 default:{}break; 2285 } 2286 if (done) break; 2287 } 2288 p->s.data += result.length; 2289 p->s.length -= result.length; 2290 return result; 2291 } 2292 2293 function MetaExpansionToken 2294 meta_expansion_token(MetaExpansionParser *p) 2295 { 2296 MetaExpansionToken result = MetaExpansionToken_EOF; 2297 meta_expansion_save(p); 2298 if (p->s.length > 0) { 2299 b32 chop = 1; 2300 switch (p->s.data[0]) { 2301 #define X(t, kind, ...) case t:{ result = MetaExpansionToken_## kind; }break; 2302 META_EXPANSION_TOKEN_LIST 2303 #undef X 2304 default:{ 2305 chop = 0; 2306 if (Between(p->s.data[0], '0', '9')) result = MetaExpansionToken_Number; 2307 else result = MetaExpansionToken_Identifier; 2308 }break; 2309 } 2310 if (chop) { 2311 str8_chop(&p->s, 1); 2312 p->s = str8_trim(p->s); 2313 } 2314 2315 switch (result) { 2316 case MetaExpansionToken_Number:{ 2317 NumberConversion integer = integer_from_str8(p->s); 2318 if (integer.result != NumberConversionResult_Success) { 2319 /* TODO(rnp): point at start */ 2320 meta_compiler_error(p->loc, "invalid integer in expansion string\n"); 2321 } 2322 p->number = integer.S64; 2323 p->s = integer.unparsed; 2324 }break; 2325 case MetaExpansionToken_Identifier:{ p->string = meta_expansion_extract_string(p); }break; 2326 default:{}break; 2327 } 2328 p->s = str8_trim(p->s); 2329 } 2330 return result; 2331 } 2332 2333 function MetaExpansionPart * 2334 meta_expansion_start_conditional(MetaContext *ctx, Arena *arena, MetaExpansionPartList *ops, 2335 MetaExpansionParser *p, MetaExpansionToken token, b32 negate) 2336 { 2337 MetaExpansionPart *result = meta_push_expansion_part(ctx, arena, ops, MetaExpansionPartKind_Conditional, 2338 str8(""), 0, p->loc); 2339 switch (token) { 2340 case MetaExpansionToken_Number:{ 2341 result->conditional.lhs.kind = MetaExpansionConditionalArgumentKind_Number; 2342 result->conditional.lhs.number = negate ? -p->number : p->number; 2343 }break; 2344 default:{}break; 2345 } 2346 return result; 2347 } 2348 2349 function void 2350 meta_expansion_end_conditional(MetaExpansionPart *ep, MetaExpansionParser *p, MetaExpansionToken token, b32 negate) 2351 { 2352 if (ep->conditional.rhs.kind != MetaExpansionConditionalArgumentKind_Invalid) { 2353 meta_compiler_error(p->loc, "invalid expansion conditional: duplicate right hand expression: '%.*s'\n", 2354 (i32)p->save.length, p->save.data); 2355 } 2356 switch (token) { 2357 case MetaExpansionToken_Number:{ 2358 ep->conditional.rhs.kind = MetaExpansionConditionalArgumentKind_Number; 2359 ep->conditional.rhs.number = negate ? -p->number : p->number; 2360 }break; 2361 default:{}break; 2362 } 2363 } 2364 2365 function MetaExpansionPartList 2366 meta_generate_expansion_set(MetaContext *ctx, Arena *arena, str8 expansion_string, MetaEntity *table, MetaLocation loc) 2367 { 2368 MetaExpansionPartList result = {0}; 2369 str8 left = {0}, inner, remainder = expansion_string; 2370 do { 2371 meta_expansion_string_split(remainder, &left, &inner, &remainder, loc); 2372 if (left.length) meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, left, table, loc); 2373 if (inner.length) { 2374 MetaExpansionParser p[1] = {{.s = inner, .loc = loc}}; 2375 2376 MetaExpansionPart *test_part = 0; 2377 b32 count_test_parts = 0; 2378 2379 for (MetaExpansionToken token = meta_expansion_token(p); 2380 token != MetaExpansionToken_EOF; 2381 token = meta_expansion_token(p)) 2382 { 2383 if (count_test_parts) test_part->conditional.instruction_skip++; 2384 switch (token) { 2385 case MetaExpansionToken_Alignment:{ 2386 meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Alignment, p->s, table, loc); 2387 }break; 2388 2389 case MetaExpansionToken_Identifier:{ 2390 meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Reference, p->string, table, loc); 2391 }break; 2392 2393 case MetaExpansionToken_TypeEval: 2394 case MetaExpansionToken_TypeEvalElements: 2395 { 2396 if (meta_expansion_token(p) != MetaExpansionToken_Identifier) { 2397 loc.column += (u32)(p->save.data - expansion_string.data); 2398 meta_expansion_expected(loc, MetaExpansionToken_Identifier, token); 2399 } 2400 MetaExpansionPartKind kind = token == MetaExpansionToken_TypeEval ? 2401 MetaExpansionPartKind_EvalKind : 2402 MetaExpansionPartKind_EvalKindCount; 2403 meta_push_expansion_part(ctx, arena, &result, kind, p->string, table, loc); 2404 }break; 2405 2406 case MetaExpansionToken_Quote:{ 2407 u8 *point = p->s.data; 2408 str8 string = meta_expansion_extract_string(p); 2409 token = meta_expansion_token(p); 2410 if (token != MetaExpansionToken_Quote) { 2411 loc.column += (u32)(point - expansion_string.data); 2412 /* TODO(rnp): point at start */ 2413 meta_compiler_error(loc, "unterminated string in expansion\n"); 2414 } 2415 meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, string, table, loc); 2416 }break; 2417 2418 case MetaExpansionToken_Dash:{ 2419 token = meta_expansion_token(p); 2420 switch (token) { 2421 case MetaExpansionToken_GreaterThan:{ 2422 if (!test_part) goto error; 2423 if (test_part->conditional.lhs.kind == MetaExpansionConditionalArgumentKind_Invalid || 2424 test_part->conditional.rhs.kind == MetaExpansionConditionalArgumentKind_Invalid) 2425 { 2426 b32 lhs = test_part->conditional.lhs.kind == MetaExpansionConditionalArgumentKind_Invalid; 2427 b32 rhs = test_part->conditional.rhs.kind == MetaExpansionConditionalArgumentKind_Invalid; 2428 if (lhs && rhs) 2429 meta_compiler_error(loc, "expansion string test terminated without arguments\n"); 2430 meta_compiler_error(loc, "expansion string test terminated without %s argument\n", 2431 lhs? "left" : "right"); 2432 } 2433 count_test_parts = 1; 2434 }break; 2435 case MetaExpansionToken_Number:{ 2436 if (test_part) meta_expansion_end_conditional(test_part, p, token, 1); 2437 else test_part = meta_expansion_start_conditional(ctx, arena, &result, p, token, 1); 2438 }break; 2439 default:{ goto error; }break; 2440 } 2441 }break; 2442 2443 case MetaExpansionToken_Number:{ 2444 if (test_part) meta_expansion_end_conditional(test_part, p, token, 0); 2445 else test_part = meta_expansion_start_conditional(ctx, arena, &result, p, token, 0); 2446 }break; 2447 2448 case MetaExpansionToken_GreaterThan: 2449 case MetaExpansionToken_LessThan: 2450 { 2451 if (test_part && test_part->conditional.op != MetaExpansionOperation_Invalid) goto error; 2452 if (!test_part) { 2453 if (result.count == 0) { 2454 meta_compiler_error(p->loc, "invalid expansion conditional: missing left hand side\n"); 2455 } 2456 2457 str8 *strings = result.data[result.count - 1].strings; 2458 MetaExpansionPartKind last_kind = result.data[result.count - 1].kind; 2459 if (last_kind != MetaExpansionPartKind_EvalKindCount && 2460 last_kind != MetaExpansionPartKind_Reference) 2461 { 2462 meta_compiler_error(p->loc, "invalid expansion conditional: left hand side not numeric\n"); 2463 } 2464 result.count--; 2465 test_part = meta_expansion_start_conditional(ctx, arena, &result, p, token, 0); 2466 if (last_kind == MetaExpansionPartKind_EvalKindCount) { 2467 test_part->conditional.lhs.kind = MetaExpansionConditionalArgumentKind_Evaluation; 2468 } else { 2469 test_part->conditional.lhs.kind = MetaExpansionConditionalArgumentKind_Reference; 2470 } 2471 test_part->conditional.lhs.strings = strings; 2472 } 2473 test_part->conditional.op = token == MetaExpansionToken_LessThan ? 2474 MetaExpansionOperation_LessThan : 2475 MetaExpansionOperation_GreaterThan; 2476 }break; 2477 2478 error: 2479 default: 2480 { 2481 meta_compiler_error(loc, "invalid nested %.*s in expansion string\n", 2482 (i32)meta_expansion_token_strings[token].length, 2483 meta_expansion_token_strings[token].data); 2484 }break; 2485 } 2486 } 2487 } 2488 } while (remainder.length); 2489 return result; 2490 } 2491 2492 function da_count 2493 meta_expand_table_entity_id(MetaContext *ctx, MetaEntry *e) 2494 { 2495 assert(e->kind == MetaEntryKind_Expand); 2496 2497 /* TODO(rnp): for now this requires that the @Table came first */ 2498 meta_entry_argument_expected(e, str8("table_name")); 2499 str8 table_name = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; 2500 2501 da_count result = meta_lookup_string_slow(ctx->entity_names.data, ctx->entity_names.count, table_name); 2502 2503 if (result < 0) meta_entry_error(e, "undefined table %.*s\n", (i32)table_name.length, table_name.data); 2504 2505 MetaEntity *table = ctx->entities.data + result; 2506 if (!meta_entity_kind_is_table[table->kind]) { 2507 str8 old_kind = meta_entity_kind_names[table->kind]; 2508 str8 wanted_kind = meta_entity_kind_names[MetaEntityKind_Table]; 2509 meta_entry_error(e, "%.*s previously defined as %.*s but should be %.*s\n", 2510 (i32)table_name.length, table_name.data, 2511 (i32)old_kind.length, old_kind.data, 2512 (i32)wanted_kind.length, wanted_kind.data); 2513 } 2514 2515 return result; 2516 } 2517 2518 function str8 2519 meta_expand_parts_to_str8_at_index(MetaContext *ctx, u64 table_index, MetaExpansionPartList parts) 2520 { 2521 Stream sb = arena_stream(ctx->arena); 2522 for EachIndex((u64)parts.count, part) { 2523 MetaExpansionPart *p = parts.data + part; 2524 u32 index = 0; 2525 if (p->kind == MetaExpansionPartKind_Reference) index = table_index; 2526 stream_append_str8(&sb, p->kind == MetaExpansionPartKind_String ? p->string : p->strings[index]); 2527 } 2528 str8 result = arena_stream_commit(ctx->arena, &sb); 2529 return result; 2530 } 2531 2532 function void 2533 meta_pack_table_begin(MetaEntry *e, MetaTable *t) 2534 { 2535 switch (e->kind) { 2536 2537 case MetaEntryKind_Enumeration: 2538 case MetaEntryKind_Flags: 2539 { 2540 read_only str8 enumeration_fields[] = {str8_comp("name")}; 2541 t->fields = (str8 *)enumeration_fields; 2542 t->field_count = countof(enumeration_fields); 2543 }break; 2544 2545 case MetaEntryKind_Bake: 2546 case MetaEntryKind_PushConstants: 2547 case MetaEntryKind_Struct: 2548 case MetaEntryKind_Union: 2549 { 2550 meta_entry_argument_expected_(e, 0, 0); 2551 #define X(_i, name, ...) str8_comp(#name), 2552 read_only str8 struct_fields[] = {META_STRUCT_FIELDS}; 2553 #undef X 2554 t->fields = (str8 *)struct_fields; 2555 t->field_count = countof(struct_fields); 2556 }break; 2557 2558 case MetaEntryKind_Table:{ 2559 meta_entry_argument_expected(e, str8("[field ...]")); 2560 MetaEntryArgument fields = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_Array); 2561 t->fields = fields.strings; 2562 t->field_count = (u32)fields.count; 2563 }break; 2564 2565 InvalidDefaultCase; 2566 } 2567 } 2568 2569 function i64 2570 meta_pack_table_entity(MetaContext *ctx, MetaEntry *e, i64 entry_count, str8 name, MetaEntityID parent) 2571 { 2572 MetaEntityKind entity_kind = MetaEntityKind_Nil; 2573 switch (e->kind) { 2574 case MetaEntryKind_Bake:{ entity_kind = MetaEntityKind_BakeParameters;}break; 2575 case MetaEntryKind_Enumeration:{ entity_kind = MetaEntityKind_Enumeration; }break; 2576 case MetaEntryKind_Flags:{ entity_kind = MetaEntityKind_Flags; }break; 2577 case MetaEntryKind_PushConstants:{entity_kind = MetaEntityKind_PushConstants; }break; 2578 case MetaEntryKind_Struct:{ entity_kind = MetaEntityKind_Struct; }break; 2579 case MetaEntryKind_Table:{ entity_kind = MetaEntityKind_Table; }break; 2580 case MetaEntryKind_Union:{ entity_kind = MetaEntityKind_Union; }break; 2581 InvalidDefaultCase; 2582 } 2583 2584 MetaEntityID entity_id = meta_intern_entity(ctx, name, entity_kind, parent, e->location, 0); 2585 2586 MetaTable table = {0}, *t = &table; 2587 meta_pack_table_begin(e, t); 2588 2589 b32 structure = e->kind == MetaEntryKind_Struct || 2590 e->kind == MetaEntryKind_Bake || 2591 e->kind == MetaEntryKind_PushConstants || 2592 e->kind == MetaEntryKind_Union; 2593 2594 MetaEntryScope scope = meta_entry_extract_scope(e, entry_count); 2595 Temp scratch; 2596 if (scope.consumed > 1) 2597 DeferLoop(scratch = temp_begin(ctx->scratch), temp_end(scratch)) 2598 { 2599 // NOTE(rnp): count expands 2600 i64 expand_count = 0; 2601 for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) 2602 if (row->kind == MetaEntryKind_Expand) 2603 expand_count++; 2604 2605 // NOTE(rnp): extract expand tables 2606 da_count *table_ids = 0; 2607 i64 table_id_index = 0; 2608 if (expand_count > 0) { 2609 table_ids = push_array(ctx->scratch, da_count, expand_count); 2610 for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) 2611 if (row->kind == MetaEntryKind_Expand) 2612 table_ids[table_id_index++] = meta_expand_table_entity_id(ctx, row); 2613 } 2614 2615 table_id_index = 0; 2616 for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) { 2617 if ((row->kind != MetaEntryKind_Array && 2618 row->kind != MetaEntryKind_Expand && 2619 row->kind != MetaEntryKind_Union && 2620 row->kind != MetaEntryKind_String) || 2621 (row->kind == MetaEntryKind_Union && !structure)) 2622 { 2623 meta_entry_nesting_error(row, e->kind); 2624 } 2625 2626 MetaEntryArgument entries = {.count = 1}; 2627 2628 if (row->kind == MetaEntryKind_Expand) { 2629 if (row + 1 == scope.one_past_last || ( 2630 row[1].kind != MetaEntryKind_Array && 2631 row[1].kind != MetaEntryKind_String)) 2632 { 2633 meta_entry_nesting_error(row + 1, row->kind); 2634 } 2635 2636 if (row[1].kind == MetaEntryKind_Array) 2637 entries.count = meta_entry_argument_expect(row + 1, 0, MetaEntryArgumentKind_Array).count; 2638 } 2639 2640 if (row->kind == MetaEntryKind_Union) { 2641 if (row->argument_count > 1) { 2642 const char *name = meta_entry_kind_strings[row->kind]; 2643 meta_compiler_error_message(row->location, "invalid nested @%s: got: ", name); 2644 meta_entry_print(row, 0, -1); 2645 fprintf(stderr, " expected: '@%s %.*s' or '@%s(array_count) %.*s'\n", 2646 name, (i32)row->name.length, row->name.data, name, (i32)row->name.length, row->name.data); 2647 meta_error(); 2648 } 2649 entries.count = 2; 2650 } 2651 2652 if (row->kind == MetaEntryKind_Array) 2653 entries.count = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_Array).count; 2654 2655 if (structure && entries.count != 2 && entries.count != 3) { 2656 meta_compiler_error(row->location, "incorrect field count for @%s entry got: %zu expected: " 2657 "[name type (elements)]\n", meta_entry_kind_strings[e->kind], 2658 (size_t)entries.count); 2659 } else if (!structure && entries.count != t->field_count) { 2660 meta_compiler_error_message(row->location, "incorrect field count for @%s entry got: %zu expected: %u\n", 2661 meta_entry_kind_strings[e->kind], (size_t)entries.count, t->field_count); 2662 fprintf(stderr, " fields: ["); 2663 for (u64 i = 0; i < t->field_count; i++) { 2664 if (i != 0) fprintf(stderr, " "); 2665 fprintf(stderr, "%.*s", (i32)t->fields[i].length, t->fields[i].data); 2666 } 2667 fprintf(stderr, "]\n"); 2668 meta_error(); 2669 } 2670 2671 if (row->kind == MetaEntryKind_Expand) { 2672 t->entry_count += ctx->entities.data[table_ids[table_id_index++]].table.entry_count; 2673 // NOTE(rnp): skip expand argument 2674 row++; 2675 } else { 2676 t->entry_count++; 2677 } 2678 } 2679 2680 t->entries = push_array(ctx->arena, str8 *, t->field_count); 2681 for (u32 field = 0; field < t->field_count; field++) 2682 t->entries[field] = push_array(ctx->arena, str8, t->entry_count); 2683 2684 u32 row_index = 0; 2685 table_id_index = 0; 2686 for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) { 2687 switch (row->kind) { 2688 case MetaEntryKind_Expand:{ 2689 row++; 2690 u64 argument_count = row->arguments ? row->arguments->count : 1; 2691 2692 MetaEntity *table = ctx->entities.data + table_ids[table_id_index++]; 2693 2694 u32 working_row_index = row_index; 2695 for EachIndex(argument_count, it) { 2696 working_row_index = row_index; 2697 str8 expand = row->arguments ? row->arguments->strings[it] : row->name; 2698 MetaExpansionPartList parts = meta_generate_expansion_set(ctx, ctx->scratch, expand, table, row->location); 2699 for EachIndex(table->table.entry_count, entry_index) 2700 t->entries[it][working_row_index++] = meta_expand_parts_to_str8_at_index(ctx, entry_index, parts); 2701 } 2702 2703 for (; row_index < working_row_index; row_index++) 2704 if (structure && argument_count == 2) 2705 t->entries[MetaStructField_Elements][row_index] = str8("1"); 2706 2707 }break; 2708 2709 case MetaEntryKind_Union:{ 2710 // NOTE(rnp): anonymous union (named union already covered by standard table syntax) 2711 t->entries[MetaStructField_Name][row_index] = str8(""); 2712 t->entries[MetaStructField_Type][row_index] = row->name; 2713 t->entries[MetaStructField_Elements][row_index] = row->argument_count ? row->arguments->string 2714 : str8("1"); 2715 }break; 2716 2717 default:{ 2718 str8 *fs = &row->name; 2719 u64 argument_count = row->arguments ? row->arguments->count : 1; 2720 if (row->arguments) 2721 fs = row->arguments->strings; 2722 2723 for (u32 field = 0; field < t->field_count; field++) 2724 t->entries[field][row_index] = fs[field]; 2725 2726 // NOTE(rnp): if we are filling out a struct the array element count is optional 2727 // and defaults to 1. fill this out here for uniformity elsewhere in the code 2728 if (structure && argument_count == 2) 2729 t->entries[MetaStructField_Elements][row_index] = str8("1"); 2730 row_index++; 2731 }break; 2732 } 2733 } 2734 } 2735 2736 MetaEntity *entity = meta_entity(ctx, entity_id); 2737 entity->table = table; 2738 2739 switch (e->kind) { 2740 case MetaEntryKind_Bake: 2741 case MetaEntryKind_Enumeration: 2742 case MetaEntryKind_Flags: 2743 case MetaEntryKind_PushConstants: 2744 case MetaEntryKind_Struct: 2745 case MetaEntryKind_Table: 2746 case MetaEntryKind_Union: 2747 {}break; 2748 2749 InvalidDefaultCase; 2750 } 2751 2752 return scope.consumed; 2753 } 2754 2755 function i64 2756 meta_pack_shader_common(MetaContext *ctx, MetaEntityID shader_id, MetaEntry *e, i64 entry_count, MetaEntityID group_entity_id) 2757 { 2758 assert(ctx->entities.data[shader_id.value].kind == MetaEntityKind_Shader); 2759 i64 result = 0; 2760 2761 switch(e->kind) { 2762 2763 case MetaEntryKind_Bake:{ 2764 e->name = push_str8_from_parts(ctx->arena, str8(""), ctx->entity_names.data[shader_id.value], str8("BakeParameters")); 2765 result = meta_pack_table_entity(ctx, e, entry_count, e->name, shader_id); 2766 }break; 2767 2768 case MetaEntryKind_Flags:{ 2769 e->name = push_str8_from_parts(ctx->arena, str8(""), ctx->entity_names.data[shader_id.value], str8("CompileFlags")); 2770 result = meta_pack_table_entity(ctx, e, entry_count, e->name, shader_id); 2771 goto reference; 2772 }break; 2773 2774 case MetaEntryKind_PushConstants:{ 2775 e->name = push_str8_from_parts(ctx->arena, str8(""), ctx->entity_names.data[shader_id.value], str8("PushConstants")); 2776 result = meta_pack_table_entity(ctx, e, entry_count, e->name, shader_id); 2777 goto reference; 2778 }break; 2779 2780 case MetaEntryKind_ShaderAlias:{ 2781 MetaEntityID alias_id = meta_intern_entity(ctx, e->name, MetaEntityKind_Shader, group_entity_id, 2782 e->location, 0); 2783 meta_entity(ctx, alias_id)->shader.kind = MetaShaderKind_Alias; 2784 meta_entity(ctx, alias_id)->shader.alias_parent_id = shader_id; 2785 }break; 2786 2787 case MetaEntryKind_Enumeration: 2788 case MetaEntryKind_Constant: 2789 case MetaEntryKind_Struct: 2790 reference: 2791 { 2792 meta_entry_argument_expected(e); 2793 // TODO(rnp): MetaIDList.data should be of type MetaEntityID 2794 MetaEntityID ref_id = meta_entity_reference(ctx, e->name, e->location); 2795 meta_intern_id(ctx, &meta_entity(ctx, shader_id)->shader.entity_reference_ids, ref_id.value); 2796 }break; 2797 2798 default:{ meta_entry_nesting_error(e, MetaEntryKind_Shader); }break; 2799 } 2800 2801 return result; 2802 } 2803 2804 function i64 2805 meta_pack_render_shader(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID group_entity_id) 2806 { 2807 assert(entries[0].kind == MetaEntryKind_RenderShader); 2808 2809 MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_Shader, 2810 group_entity_id, entries->location, 0); 2811 meta_entity(ctx, entity_id)->shader.kind = MetaShaderKind_Render; 2812 2813 meta_entry_argument_expected(entries); 2814 2815 MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count); 2816 if (scope.consumed > 1) { 2817 for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) { 2818 switch (e->kind) { 2819 2820 case MetaEntryKind_VertexShader:{ 2821 if (meta_entity(ctx, entity_id)->shader.files[0].length) 2822 meta_entry_error(e, "primitive shader file redefined\n"); 2823 meta_entity(ctx, entity_id)->shader.files[0] = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; 2824 meta_entity(ctx, entity_id)->shader.render.kind = MetaShaderPrimitiveKind_Vertex; 2825 }break; 2826 2827 case MetaEntryKind_FragmentShader:{ 2828 if (meta_entity(ctx, entity_id)->shader.files[1].length) 2829 meta_entry_error(e, "fragment shader file redefined\n"); 2830 meta_entity(ctx, entity_id)->shader.files[1] = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; 2831 }break; 2832 2833 default:{ 2834 e += meta_pack_shader_common(ctx, entity_id, e, scope.one_past_last - e, group_entity_id); 2835 }break; 2836 } 2837 } 2838 } 2839 return scope.consumed; 2840 } 2841 2842 function i64 2843 meta_pack_compute_shader(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID group_entity_id) 2844 { 2845 assert(entries[0].kind == MetaEntryKind_Shader); 2846 2847 MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_Shader, group_entity_id, 2848 entries->location, 0); 2849 meta_entity(ctx, entity_id)->shader.kind = MetaShaderKind_Compute; 2850 2851 if (entries->argument_count > 1) { 2852 meta_entry_argument_expected(entries, str8("[file_name]")); 2853 } else if (entries->argument_count == 1) { 2854 str8 shader_file = meta_entry_argument_expect(entries, 0, MetaEntryArgumentKind_String).string; 2855 meta_entity(ctx, entity_id)->shader.files[0] = shader_file; 2856 } 2857 2858 MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count); 2859 if (scope.consumed > 1) { 2860 for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) 2861 e += meta_pack_shader_common(ctx, entity_id, e, scope.one_past_last - e, group_entity_id); 2862 } else { 2863 assert(scope.consumed == 1); 2864 // TODO(rnp): some functions (@Expand) expect no scope and that the next entry 2865 // is treated as in scope; here we do not want that behaviour. 2866 scope.consumed = 0; 2867 } 2868 return scope.consumed; 2869 } 2870 2871 function i64 2872 meta_pack_shader_group(MetaContext *ctx, MetaEntry *entries, i64 entry_count) 2873 { 2874 assert(entries->kind == MetaEntryKind_ShaderGroup); 2875 2876 MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_ShaderGroup, 2877 meta_root_entity_id(ctx), entries->location, 0); 2878 2879 MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count); 2880 if (scope.consumed > 1) { 2881 for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) { 2882 switch (e->kind) { 2883 case MetaEntryKind_RenderShader:{ 2884 e += meta_pack_render_shader(ctx, e, scope.one_past_last - e, entity_id); 2885 }break; 2886 case MetaEntryKind_Shader:{ 2887 e += meta_pack_compute_shader(ctx, e, scope.one_past_last - e, entity_id); 2888 }break; 2889 default:{meta_entry_nesting_error(e, MetaEntryKind_ShaderGroup);}break; 2890 } 2891 } 2892 } 2893 return scope.consumed; 2894 } 2895 2896 function i64 2897 meta_pack_references(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID parent, 2898 str8 scope_name, str8 prefix) 2899 { 2900 MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count); 2901 for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) { 2902 switch (e->kind) { 2903 case MetaEntryKind_Struct: 2904 case MetaEntryKind_Union: 2905 { 2906 meta_entity_reference_reference(ctx, e->name, scope_name, e->location, parent, prefix); 2907 }break; 2908 default:{meta_entry_nesting_error(e, entries->kind);}break; 2909 } 2910 } 2911 return scope.consumed; 2912 } 2913 2914 function str8 * 2915 meta_expand_to_str8_array(MetaContext *ctx, str8 expand, MetaEntity *table, MetaLocation location) 2916 { 2917 str8 *result = 0; 2918 Temp scratch; 2919 DeferLoop(scratch = temp_begin(ctx->scratch), temp_end(scratch)) 2920 { 2921 MetaExpansionPartList parts = meta_generate_expansion_set(ctx, ctx->scratch, expand, table, location); 2922 result = push_array(ctx->arena, str8, table->table.entry_count); 2923 for EachIndex(table->table.entry_count, expansion) 2924 result[expansion] = meta_expand_parts_to_str8_at_index(ctx, expansion, parts); 2925 } 2926 return result; 2927 } 2928 2929 function i64 2930 meta_expand(MetaContext *ctx, MetaEntry *e, i64 entry_count, MetaEmitOperationList *ops) 2931 { 2932 assert(e->kind == MetaEntryKind_Expand); 2933 2934 MetaEntity *table = ctx->entities.data + meta_expand_table_entity_id(ctx, e); 2935 str8 table_name = ctx->entity_names.data[da_index(table, &ctx->entities)]; 2936 2937 MetaEntryScope scope = meta_entry_extract_scope(e, entry_count); 2938 for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) { 2939 switch (row->kind) { 2940 case MetaEntryKind_String:{ 2941 if (!ops) goto error; 2942 2943 MetaExpansionPartList parts = meta_generate_expansion_set(ctx, ctx->arena, row->name, table, row->location); 2944 2945 MetaEmitOperation *op = da_push(ctx->arena, ops); 2946 op->kind = MetaEmitOperationKind_Expand; 2947 op->location = row->location; 2948 op->expansion_operation.parts = parts.data; 2949 op->expansion_operation.part_count = (u32)parts.count; 2950 op->expansion_operation.table_entity_id = da_index(table, &ctx->entities); 2951 }break; 2952 2953 case MetaEntryKind_Enumeration: 2954 case MetaEntryKind_Flags: 2955 { 2956 if (ops) meta_entry_nesting_error(row, MetaEntryKind_Emit); 2957 2958 meta_entry_argument_expected(row, str8("`raw_string`")); 2959 str8 expand = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_String).string; 2960 2961 MetaEntityKind entity_kind = row->kind == MetaEntryKind_Flags ? MetaEntityKind_Flags : MetaEntityKind_Enumeration; 2962 MetaEntityID entity_id = meta_intern_entity(ctx, row->name, entity_kind, meta_root_entity_id(ctx), 2963 row->location, 0); 2964 MetaEntry entry = {.kind = row->kind}; 2965 MetaEntity *new = ctx->entities.data + entity_id.value; 2966 meta_pack_table_begin(&entry, &new->table); 2967 new->table.entries = push_array(ctx->arena, str8 *, new->table.field_count); 2968 new->table.entry_count = table->table.entry_count; 2969 new->table.entries[0] = meta_expand_to_str8_array(ctx, expand, table, row->location); 2970 }break; 2971 2972 case MetaEntryKind_Struct: 2973 case MetaEntryKind_Union: 2974 { 2975 if (ops) meta_entry_nesting_error(row, MetaEntryKind_Emit); 2976 MetaEntryArgument fields = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_Array); 2977 if (fields.count != 2 && fields.count != 3) { 2978 meta_compiler_error(row->location, "Invalid arguments in table expansion: '%.*s'\n" 2979 "Union expansion requires field names for member names, type names, " 2980 "and optionally element counts.\n", (i32)table_name.length, table_name.data); 2981 } 2982 2983 MetaEntityKind entity_kind = row->kind == MetaEntryKind_Struct ? MetaEntityKind_Struct : MetaEntityKind_Union; 2984 MetaEntityID entity_id = meta_intern_entity(ctx, row->name, entity_kind, 2985 meta_root_entity_id(ctx), row->location, 0); 2986 MetaEntry entry = {.kind = row->kind}; 2987 MetaEntity *new = ctx->entities.data + entity_id.value; 2988 meta_pack_table_begin(&entry, &new->table); 2989 new->table.entries = push_array(ctx->arena, str8 *, new->table.field_count); 2990 new->table.entry_count = table->table.entry_count; 2991 new->table.entries[MetaStructField_Name] = meta_expand_to_str8_array(ctx, fields.strings[0], 2992 table, row->location); 2993 new->table.entries[MetaStructField_Type] = meta_expand_to_str8_array(ctx, fields.strings[1], 2994 table, row->location); 2995 if (fields.count == 3) { 2996 new->table.entries[MetaStructField_Elements] = meta_expand_to_str8_array(ctx, fields.strings[2], 2997 table, row->location); 2998 } else { 2999 new->table.entries[MetaStructField_Elements] = push_array(ctx->arena, str8, table->table.entry_count); 3000 for EachIndex(new->table.entry_count, entry) 3001 new->table.entries[MetaStructField_Elements][entry] = str8("1"); 3002 } 3003 }break; 3004 3005 error: 3006 default: 3007 { 3008 meta_entry_nesting_error(row, MetaEntryKind_Expand); 3009 }break; 3010 } 3011 } 3012 return scope.consumed; 3013 } 3014 3015 function void 3016 meta_embed(MetaContext *ctx, MetaEntry *e, i64 entry_count) 3017 { 3018 assert(e->kind == MetaEntryKind_Embed); 3019 3020 meta_entry_argument_expected(e, str8("filename")); 3021 str8 filename = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; 3022 3023 MetaEmitOperationList *ops = da_push(ctx->arena, ctx->emit_sets + MetaEmitLang_C); 3024 if (e->name.length == 0) meta_entry_error(e, "name must be provided for output array"); 3025 3026 MetaEmitOperation *op; 3027 op = da_push(ctx->arena, ops); 3028 op->kind = MetaEmitOperationKind_String; 3029 op->string = push_str8_from_parts(ctx->arena, str8(""), str8("read_only u8 "), e->name, str8("[] = {")); 3030 3031 op = da_push(ctx->arena, ops); 3032 op->kind = MetaEmitOperationKind_FileBytes; 3033 op->string = filename; 3034 3035 op = da_push(ctx->arena, ops); 3036 op->kind = MetaEmitOperationKind_String; 3037 op->string = str8("};"); 3038 } 3039 3040 function MetaKind 3041 meta_map_kind(str8 kind, str8 table_name, MetaLocation location) 3042 { 3043 i64 id = meta_lookup_string_slow(meta_kind_meta_types, MetaKind_Count, kind); 3044 if (id < 0) { 3045 meta_compiler_error(location, "Invalid Kind in '%.*s' table expansion: %.*s\n", 3046 (i32)table_name.length, table_name.data, (i32)kind.length, kind.data); 3047 } 3048 MetaKind result = (MetaKind)id; 3049 return result; 3050 } 3051 3052 function MetaEmitLang 3053 meta_map_emit_lang(str8 lang, MetaEntry *e) 3054 { 3055 #define X(k, ...) str8_comp(#k), 3056 read_only str8 meta_lang_strings[] = {META_EMIT_LANG_LIST}; 3057 #undef X 3058 3059 i64 id = meta_lookup_string_slow(meta_lang_strings, MetaEmitLang_Count, lang); 3060 if (id < 0) { 3061 #define X(k, ...) #k ", " 3062 meta_entry_error(e, "Unknown Emit Language: '%.*s'\nPossible Values: " 3063 META_EMIT_LANG_LIST "\n", (i32)lang.length, lang.data); 3064 #undef X 3065 } 3066 MetaEmitLang result = (MetaEmitLang)id; 3067 return result; 3068 } 3069 3070 function void 3071 meta_pack_constant(MetaContext *ctx, MetaEntry *e) 3072 { 3073 assert(e->kind == MetaEntryKind_Constant); 3074 3075 MetaEntityID entity_id = meta_intern_entity(ctx, e->name, MetaEntityKind_Constant, 3076 meta_root_entity_id(ctx), e->location, 0); 3077 3078 meta_entry_argument_expected(e, str8("value")); 3079 str8 value = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; 3080 3081 NumberConversion number = number_from_str8(value); 3082 if (number.result != NumberConversionResult_Success || number.unparsed.length != 0) { 3083 meta_compiler_error(e->location, "Invalid integer in definition of Constant '%.*s': %.*s\n", 3084 (i32)e->name.length, e->name.data, (i32)value.length, value.data); 3085 } 3086 3087 MetaEntity *entity = meta_entity(ctx, entity_id); 3088 if (number.kind == NumberConversionKind_Float) { 3089 entity->constant.kind = MetaConstantKind_Float; 3090 entity->constant.F64 = number.F64; 3091 } else { 3092 entity->constant.kind = MetaConstantKind_Integer; 3093 entity->constant.U64 = number.U64; 3094 } 3095 } 3096 3097 function i64 3098 meta_pack_emit(MetaContext *ctx, MetaEntry *e, i64 entry_count) 3099 { 3100 assert(e->kind == MetaEntryKind_Emit); 3101 3102 MetaEmitLang lang = MetaEmitLang_C; 3103 if (e->argument_count) { 3104 meta_entry_argument_expected(e, str8("emit_language")); 3105 str8 name = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; 3106 lang = meta_map_emit_lang(name, e); 3107 } 3108 3109 MetaEmitOperationList *ops = da_push(ctx->arena, ctx->emit_sets + lang); 3110 /* TODO(rnp): probably we should check this is unique */ 3111 ops->filename = e->name; 3112 3113 MetaEntryScope scope = meta_entry_extract_scope(e, entry_count); 3114 for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) { 3115 switch (row->kind) { 3116 case MetaEntryKind_String:{ 3117 MetaEmitOperation *op = da_push(ctx->arena, ops); 3118 op->kind = MetaEmitOperationKind_String; 3119 op->string = row->name; 3120 op->location = row->location; 3121 }break; 3122 case MetaEntryKind_Expand:{ 3123 row += meta_expand(ctx, row, entry_count - (row - e), ops); 3124 }break; 3125 default:{ meta_entry_nesting_error(row, MetaEntryKind_Emit); }break; 3126 } 3127 } 3128 return scope.consumed; 3129 } 3130 3131 function CommandList 3132 meta_extract_emit_file_dependencies(MetaContext *ctx, Arena *arena) 3133 { 3134 CommandList result = {0}; 3135 for (i64 set = 0; set < ctx->emit_sets[MetaEmitLang_C].count; set++) { 3136 MetaEmitOperationList *ops = ctx->emit_sets[MetaEmitLang_C].data + set; 3137 for (i64 opcode = 0; opcode < ops->count; opcode++) { 3138 MetaEmitOperation *op = ops->data + opcode; 3139 switch (op->kind) { 3140 case MetaEmitOperationKind_FileBytes:{ 3141 str8 filename = push_str8_from_parts(arena, str8(OS_PATH_SEPARATOR), ctx->directory, op->string); 3142 *da_push(arena, &result) = (c8 *)filename.data; 3143 }break; 3144 default:{}break; 3145 } 3146 } 3147 } 3148 return result; 3149 } 3150 3151 function void 3152 metagen_push_byte_array(MetaprogramContext *m, str8 bytes) 3153 { 3154 for (i64 i = 0; i < bytes.length; i++) { 3155 b32 end_line = (i != 0) && (i % 16) == 0; 3156 if (i != 0) meta_push(m, end_line ? str8(",") : str8(", ")); 3157 if (end_line) meta_end_line(m); 3158 if ((i % 16) == 0) meta_indent(m); 3159 meta_push(m, str8("0x")); 3160 meta_push_u64_hex(m, bytes.data[i]); 3161 } 3162 meta_end_line(m); 3163 } 3164 3165 function void 3166 metagen_push_table(MetaprogramContext *m, str8 row_start, str8 row_end, str8 **column_strings, u64 rows, u64 columns) 3167 { 3168 Temp scratch; 3169 DeferLoop(scratch = temp_begin(m->scratch), temp_end(scratch)) 3170 { 3171 u32 *column_widths = 0; 3172 if (columns > 1) { 3173 column_widths = push_array(m->scratch, u32, columns - 1); 3174 for (u64 column = 0; column < columns - 1; column++) { 3175 str8 *strings = column_strings[column]; 3176 for (u64 row = 0; row < rows; row++) 3177 column_widths[column] = Max(column_widths[column], (u32)strings[row].length); 3178 } 3179 } 3180 3181 for (u64 row = 0; row < rows; row++) { 3182 meta_begin_line(m, row_start); 3183 for (u64 column = 0; column < columns; column++) { 3184 str8 text = column_strings[column][row]; 3185 meta_push(m, text); 3186 i32 pad = columns > 1 ? 1 : 0; 3187 if (column_widths && column < columns - 1) 3188 pad += (i32)column_widths[column] - (i32)text.length; 3189 if (column < columns - 1) meta_pad(m, ' ', pad); 3190 } 3191 meta_end_line(m, row_end); 3192 } 3193 } 3194 } 3195 3196 function i64 3197 meta_expansion_part_conditional_argument(MetaExpansionConditionalArgument a, u32 entry, 3198 str8 table_name, MetaLocation loc) 3199 { 3200 i64 result = 0; 3201 switch (a.kind) { 3202 case MetaExpansionConditionalArgumentKind_Number:{ 3203 result = a.number; 3204 }break; 3205 3206 case MetaExpansionConditionalArgumentKind_Evaluation: 3207 { 3208 str8 string = a.strings[entry]; 3209 MetaKind kind = meta_map_kind(string, table_name, loc); 3210 result = meta_kind_elements[kind]; 3211 }break; 3212 3213 case MetaExpansionConditionalArgumentKind_Reference:{ 3214 str8 string = a.strings[entry]; 3215 NumberConversion integer = integer_from_str8(string); 3216 if (integer.result != NumberConversionResult_Success) { 3217 meta_compiler_error(loc, "Invalid integer in '%.*s' table expansion: %.*s\n", 3218 (i32)table_name.length, table_name.data, (i32)string.length, string.data); 3219 } 3220 result = integer.S64; 3221 }break; 3222 3223 InvalidDefaultCase; 3224 } 3225 3226 return result; 3227 } 3228 3229 function b32 3230 meta_expansion_part_conditional(MetaExpansionPart *p, u32 entry, str8 table_name, MetaLocation loc) 3231 { 3232 assert(p->kind == MetaExpansionPartKind_Conditional); 3233 b32 result = 0; 3234 i64 lhs = meta_expansion_part_conditional_argument(p->conditional.lhs, entry, table_name, loc); 3235 i64 rhs = meta_expansion_part_conditional_argument(p->conditional.rhs, entry, table_name, loc); 3236 switch (p->conditional.op) { 3237 case MetaExpansionOperation_LessThan:{ result = lhs < rhs; }break; 3238 case MetaExpansionOperation_GreaterThan:{ result = lhs > rhs; }break; 3239 InvalidDefaultCase; 3240 } 3241 return result; 3242 } 3243 3244 function void 3245 metagen_run_emit(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationList *ops, const str8 *evaluation_table) 3246 { 3247 for (i64 opcode = 0; opcode < ops->count; opcode++) { 3248 MetaEmitOperation *op = ops->data + opcode; 3249 switch (op->kind) { 3250 case MetaEmitOperationKind_String:{ meta_push_line(m, op->string); }break; 3251 case MetaEmitOperationKind_FileBytes:{ 3252 Temp scratch; 3253 DeferLoop(scratch = temp_begin(m->scratch), temp_end(scratch)) 3254 { 3255 str8 filename = push_str8_from_parts(m->scratch, str8(OS_PATH_SEPARATOR), ctx->directory, op->string); 3256 str8 file = os_read_entire_file(m->scratch, (c8 *)filename.data); 3257 m->indentation_level++; 3258 metagen_push_byte_array(m, file); 3259 m->indentation_level--; 3260 } 3261 }break; 3262 case MetaEmitOperationKind_Expand:{ 3263 Temp scratch; 3264 DeferLoop(scratch = temp_begin(m->scratch), temp_end(scratch)) 3265 { 3266 MetaEmitOperationExpansion *eop = &op->expansion_operation; 3267 MetaTable *t = &ctx->entities.data[eop->table_entity_id].table; 3268 str8 table_name = ctx->entity_names.data[eop->table_entity_id]; 3269 3270 u32 alignment_count = 1; 3271 u32 evaluation_count = 0; 3272 for (u32 part = 0; part < eop->part_count; part++) { 3273 if (eop->parts[part].kind == MetaExpansionPartKind_Alignment) 3274 alignment_count++; 3275 if (eop->parts[part].kind == MetaExpansionPartKind_EvalKind || 3276 eop->parts[part].kind == MetaExpansionPartKind_EvalKindCount) 3277 evaluation_count++; 3278 } 3279 3280 MetaKind **evaluation_columns = push_array(m->scratch, MetaKind *, evaluation_count); 3281 for (u32 column = 0; column < evaluation_count; column++) 3282 evaluation_columns[column] = push_array(m->scratch, MetaKind, t->entry_count); 3283 3284 for (u32 part = 0; part < eop->part_count; part++) { 3285 u32 eval_column = 0; 3286 MetaExpansionPart *p = eop->parts + part; 3287 if (p->kind == MetaExpansionPartKind_EvalKind) { 3288 for (u32 entry = 0; entry < t->entry_count; entry++) { 3289 evaluation_columns[eval_column][entry] = meta_map_kind(p->strings[entry], 3290 table_name, op->location); 3291 } 3292 eval_column++; 3293 } 3294 } 3295 3296 str8 **columns = push_array(m->scratch, str8 *, alignment_count); 3297 for (u32 column = 0; column < alignment_count; column++) 3298 columns[column] = push_array(m->scratch, str8, t->entry_count); 3299 3300 Stream sb = arena_stream(m->scratch); 3301 for (u32 entry = 0; entry < t->entry_count; entry++) { 3302 u32 column = 0; 3303 u32 eval_column = 0; 3304 for (u32 part = 0; part < eop->part_count; part++) { 3305 MetaExpansionPart *p = eop->parts + part; 3306 switch (p->kind) { 3307 case MetaExpansionPartKind_Alignment:{ 3308 columns[column][entry] = arena_stream_commit_and_reset(m->scratch, &sb); 3309 column++; 3310 }break; 3311 3312 case MetaExpansionPartKind_Conditional:{ 3313 if (!meta_expansion_part_conditional(p, entry, table_name, op->location)) 3314 part += p->conditional.instruction_skip; 3315 }break; 3316 3317 case MetaExpansionPartKind_EvalKind:{ 3318 str8 kind = evaluation_table[evaluation_columns[eval_column][entry]]; 3319 stream_append_str8(&sb, kind); 3320 }break; 3321 3322 case MetaExpansionPartKind_EvalKindCount:{ 3323 stream_append_u64(&sb, meta_kind_elements[evaluation_columns[eval_column][entry]]); 3324 }break; 3325 3326 case MetaExpansionPartKind_Reference: 3327 case MetaExpansionPartKind_String: 3328 { 3329 str8 string = p->kind == MetaExpansionPartKind_Reference ? p->strings[entry] : p->string; 3330 stream_append_str8(&sb, string); 3331 }break; 3332 } 3333 } 3334 3335 columns[column][entry] = arena_stream_commit_and_reset(m->scratch, &sb); 3336 } 3337 metagen_push_table(m, str8(""), str8(""), columns, t->entry_count, alignment_count); 3338 } 3339 }break; 3340 InvalidDefaultCase; 3341 } 3342 } 3343 meta_end_line(m); 3344 } 3345 3346 function void 3347 metagen_run_emit_set(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationListSet *emit_set, 3348 const str8 *evaluation_table) 3349 { 3350 for (i64 set = 0; set < emit_set->count; set++) { 3351 MetaEmitOperationList *ops = emit_set->data + set; 3352 metagen_run_emit(m, ctx, ops, evaluation_table); 3353 } 3354 } 3355 3356 function i32 3357 meta_struct_member_elements(MetaContext *ctx, MetaStruct *s, u32 member) 3358 { 3359 assert(member < s->info.member_count); 3360 i32 result = s->elements[member]; 3361 if (s->member_flags[member] & MetaBuildStructMemberFlag_ReferenceElements) 3362 result = (i32)meta_entity(ctx, (MetaEntityID){result})->constant.U64; 3363 if (s->member_flags[member] & MetaBuildStructMemberFlag_EnumerationCount) 3364 result = (i32)meta_entity(ctx, (MetaEntityID){result})->table.entry_count; 3365 return result; 3366 } 3367 3368 function void 3369 metagen_push_counted_enum_body(MetaprogramContext *m, str8 kind, str8 prefix, str8 mid, str8 suffix, 3370 str8 *ids, i64 ids_count) 3371 { 3372 i64 max_id_length = 0; 3373 for (i64 id = 0; id < ids_count; id++) 3374 max_id_length = Max(max_id_length, ids[id].length); 3375 3376 for (i64 id = 0; id < ids_count; id++) { 3377 meta_begin_line(m, prefix, kind, ids[id]); 3378 meta_pad(m, ' ', 1 + (i32)(max_id_length - ids[id].length)); 3379 meta_push(m, mid); 3380 meta_push_u64(m, (u64)id); 3381 meta_end_line(m, suffix); 3382 } 3383 } 3384 3385 function void 3386 metagen_push_counted_enum_body_from_ids(MetaprogramContext *m, str8 kind, str8 prefix, str8 mid, str8 suffix, 3387 da_count *ids, str8 *id_names, da_count ids_count) 3388 { 3389 i64 max_id_length = 0; 3390 for (i64 id = 0; id < ids_count; id++) 3391 max_id_length = Max(max_id_length, id_names[ids[id]].length); 3392 3393 for (i64 id = 0; id < ids_count; id++) { 3394 meta_begin_line(m, prefix, kind, id_names[ids[id]]); 3395 meta_pad(m, ' ', 1 + (i32)(max_id_length - id_names[ids[id]].length)); 3396 meta_push(m, mid); 3397 meta_push_i64(m, id); 3398 meta_end_line(m, suffix); 3399 } 3400 } 3401 3402 function void 3403 metagen_push_c_enum(MetaprogramContext *m, str8 kind, b32 flags, str8 *ids, i64 ids_count) 3404 { 3405 str8 kind_full = push_str8_from_parts(m->scratch, str8(""), kind, str8("_")); 3406 meta_begin_scope(m, str8("typedef enum {")); 3407 metagen_push_counted_enum_body(m, kind_full, str8(""), flags ? str8("= 1 << ") : str8("= "), str8(","), ids, ids_count); 3408 if (!flags) meta_push_line(m, kind_full, str8("Count,")); 3409 meta_end_scope(m, str8("} "), kind, str8(";\n")); 3410 } 3411 3412 typedef enum { 3413 MetaPushStructStyle_C, 3414 MetaPushStructStyle_MATLAB, 3415 MetaPushStructStyle_Count, 3416 } MetaPushStructStyle; 3417 3418 typedef struct { 3419 MetaPushStructStyle layout_style; 3420 MetaPushStructStyle union_style; 3421 MetaPushStructStyle element_count_style; 3422 str8 *base_types; 3423 u8 *base_type_element_count_scales; 3424 str8 prefix; 3425 str8 suffix; 3426 str8 str_element_prefix; 3427 } MetaPushStructParameters; 3428 3429 function void 3430 meta_push_struct_body(MetaContext *ctx, MetaprogramContext *m, MetaEntity *struct_entity, 3431 MetaPushStructParameters p) 3432 { 3433 struct stack_item {MetaEntity *se; u32 member_offset;} init[16]; 3434 struct { 3435 struct stack_item *data; 3436 da_count count; 3437 da_count capacity; 3438 } stack = {init, 0, countof(init)}; 3439 3440 Temp scratch = temp_begin(m->scratch); 3441 3442 u32 max_member_count = 0; 3443 *da_push(m->scratch, &stack) = (struct stack_item){struct_entity, 0}; 3444 while (stack.count > 0) { 3445 stack.count--; 3446 MetaEntity *se = stack.data[stack.count].se; 3447 MetaStruct *s = ctx->struct_infos + se->table.struct_info_id; 3448 max_member_count = Max(s->info.member_count, max_member_count); 3449 3450 u32 member = stack.data[stack.count].member_offset; 3451 while (member < s->info.member_count) { 3452 if (s->members[member].length == 0) { 3453 assert(s->member_flags[member] & MetaStructMemberFlag_ReferenceType); 3454 *da_push(ctx->scratch, &stack) = (struct stack_item){se, member + 1}; 3455 *da_push(ctx->scratch, &stack) = (struct stack_item){ctx->entities.data + s->type_ids[member], 0}; 3456 break; 3457 } 3458 member++; 3459 } 3460 } 3461 3462 str8 *columns[2]; 3463 columns[0] = push_array(m->scratch, str8, max_member_count); 3464 columns[1] = push_array(m->scratch, str8, max_member_count); 3465 3466 u32 row = 0, scope = 0; 3467 *da_push(m->scratch, &stack) = (struct stack_item){struct_entity, 0}; 3468 while (stack.count > 0) { 3469 stack.count--; 3470 MetaEntity *se = stack.data[stack.count].se; 3471 MetaStruct *s = ctx->struct_infos + se->table.struct_info_id; 3472 u32 member = stack.data[stack.count].member_offset; 3473 3474 while (member < s->info.member_count) { 3475 b32 type_reference = (s->member_flags[member] & MetaStructMemberFlag_ReferenceType) != 0; 3476 i32 type_id = s->type_ids[member]; 3477 str8 member_name = s->members[member]; 3478 3479 // TODO(rnp): this should get refeactored to build a MetaStructMember then use 3480 // some common function for printing that instead. If we need another print style 3481 // this is going to be quite a mess 3482 3483 assert(member_name.length != 0 || type_reference); 3484 3485 if (s->members[member].length == 0 && 3486 (p.union_style != MetaPushStructStyle_MATLAB || ctx->entities.data[type_id].kind != MetaEntityKind_Union)) 3487 { 3488 *da_push(m->scratch, &stack) = (struct stack_item){se, member + 1}; 3489 *da_push(m->scratch, &stack) = (struct stack_item){ctx->entities.data + type_id, 0}; 3490 3491 MetaStruct *ss = ctx->struct_infos + ctx->entities.data[type_id].table.struct_info_id; 3492 if (p.layout_style == MetaPushStructStyle_C && ss->info.flags & MetaStructFlag_Union) { 3493 metagen_push_table(m, p.prefix, p.suffix, columns, row, 2); 3494 meta_begin_scope(m, str8("union {")); 3495 row = 0; 3496 scope++; 3497 } 3498 3499 break; 3500 } else { 3501 Stream sb = arena_stream(m->scratch); 3502 3503 b32 enum_count = (s->member_flags[member] & MetaBuildStructMemberFlag_EnumerationCount) != 0; 3504 b32 elements_reference = enum_count || (s->member_flags[member] & MetaBuildStructMemberFlag_ReferenceElements) != 0; 3505 3506 u32 resolved_element_count = meta_struct_member_elements(ctx, s, member); 3507 3508 // NOTE(rnp): member name column 3509 { 3510 read_only str8 elements_count_open[MetaPushStructStyle_Count] = { 3511 [MetaPushStructStyle_C] = str8_comp("["), 3512 [MetaPushStructStyle_MATLAB] = str8_comp("("), 3513 }; 3514 read_only str8 elements_count_close[MetaPushStructStyle_Count] = { 3515 [MetaPushStructStyle_C] = str8_comp("]"), 3516 [MetaPushStructStyle_MATLAB] = str8_comp(")"), 3517 }; 3518 read_only i32 name_column[MetaPushStructStyle_Count] = { 3519 [MetaPushStructStyle_C] = 1, 3520 [MetaPushStructStyle_MATLAB] = 0, 3521 }; 3522 3523 if (type_reference && p.union_style == MetaPushStructStyle_MATLAB) { 3524 MetaEntity *re = ctx->entities.data + type_id; 3525 MetaStruct *rs = ctx->struct_infos + re->table.struct_info_id; 3526 if (member_name.length == 0) { 3527 assert(rs->info.flags & MetaStructFlag_Union); 3528 member_name = str8("data"); 3529 } 3530 if (rs->info.flags & MetaStructFlag_Union) 3531 resolved_element_count *= rs->info.size; 3532 } else if (!type_reference && p.base_type_element_count_scales) { 3533 resolved_element_count *= p.base_type_element_count_scales[type_id]; 3534 } 3535 3536 if (resolved_element_count > 1 || p.element_count_style == MetaPushStructStyle_MATLAB) { 3537 if ((s->info.flags & MetaStructFlag_ContainsPointer) && p.layout_style == MetaPushStructStyle_C) 3538 stream_append_str8(&sb, resolved_element_count == 0 ? str8("*") : str8(" ")); 3539 3540 stream_append_str8s(&sb, member_name, elements_count_open[p.layout_style]); 3541 if (elements_reference && p.element_count_style != MetaPushStructStyle_MATLAB) { 3542 stream_append_str8s(&sb, p.str_element_prefix, ctx->entity_names.data[s->elements[member]]); 3543 if (enum_count) stream_append_str8(&sb, str8("_Count")); 3544 } else { 3545 if (p.element_count_style == MetaPushStructStyle_MATLAB) 3546 stream_append_str8(&sb, resolved_element_count ? str8("1, ") : str8("1, :")); 3547 if (resolved_element_count) stream_append_u64(&sb, resolved_element_count); 3548 } 3549 stream_append_str8(&sb, elements_count_close[p.layout_style]); 3550 } else { 3551 if ((s->info.flags & MetaStructFlag_ContainsPointer) && p.layout_style == MetaPushStructStyle_C) 3552 stream_append_str8(&sb, resolved_element_count == 0 ? str8("*") : str8(" ")); 3553 stream_append_str8(&sb, member_name); 3554 } 3555 3556 columns[name_column[p.layout_style]][row] = arena_stream_commit_and_reset(m->scratch, &sb); 3557 } 3558 3559 // NOTE(rnp): type column 3560 { 3561 read_only i32 type_column[MetaPushStructStyle_Count] = { 3562 [MetaPushStructStyle_C] = 0, 3563 [MetaPushStructStyle_MATLAB] = 1, 3564 }; 3565 3566 if (type_reference) { 3567 MetaEntity *re = ctx->entities.data + type_id; 3568 MetaStruct *rs = 0; 3569 3570 if (meta_entity_kind_is_struct[re->kind]) 3571 rs = ctx->struct_infos + re->table.struct_info_id; 3572 3573 if (rs && (rs->info.flags & MetaStructFlag_Union) && p.union_style == MetaPushStructStyle_MATLAB) { 3574 stream_append_str8(&sb, p.base_types[MetaKind_U8]); 3575 if (p.layout_style == MetaPushStructStyle_MATLAB) 3576 stream_append_str8(&sb, str8(" % +")); 3577 } else if (re->kind == MetaEntityKind_Enumeration && p.layout_style == MetaPushStructStyle_MATLAB) { 3578 // NOTE(rnp): matlab enumerations are int32 if we make this uint32 3579 // MATLAB won't fuck up the type when the field is assigned 3580 stream_append_str8(&sb, p.base_types[MetaKind_U32]); 3581 if (p.layout_style == MetaPushStructStyle_MATLAB) 3582 stream_append_str8(&sb, str8(" % ")); 3583 } else { 3584 if (p.layout_style == MetaPushStructStyle_MATLAB) { 3585 // NOTE(rnp): matlab has really broken requirements around sub structures 3586 // we can only use an opaque struct here 3587 stream_append_str8(&sb, str8("struct % ")); 3588 } else { 3589 str8 name = rs ? rs->info.name : ctx->entity_names.data[type_id]; 3590 stream_append_str8s(&sb, p.str_element_prefix, name); 3591 } 3592 } 3593 3594 if (p.layout_style == MetaPushStructStyle_MATLAB) { 3595 stream_append_str8s(&sb, p.str_element_prefix, 3596 rs ? rs->info.name : ctx->entity_names.data[type_id]); 3597 } 3598 } else { 3599 stream_append_str8(&sb, p.base_types[type_id]); 3600 } 3601 3602 columns[type_column[p.layout_style]][row] = arena_stream_commit_and_reset(m->scratch, &sb); 3603 } 3604 3605 row++; 3606 member++; 3607 } 3608 } 3609 3610 if (member == s->info.member_count && s->info.flags & MetaStructFlag_Union && p.layout_style == MetaPushStructStyle_C) { 3611 metagen_push_table(m, p.prefix, p.suffix, columns, row, 2); 3612 while (scope > 0) { 3613 meta_end_scope(m, str8("};")); 3614 scope--; 3615 } 3616 row = 0; 3617 } 3618 } 3619 metagen_push_table(m, p.prefix, p.suffix, columns, row, 2); 3620 3621 temp_end(scratch); 3622 } 3623 3624 function void 3625 meta_push_matlab_properties(MetaprogramContext *m, MetaContext *ctx, MetaStruct *meta_struct) 3626 { 3627 3628 DeferLoop(meta_begin_scope(m, str8("properties")), meta_end_scope(m, str8("end"))) 3629 { 3630 meta_push_struct_body(ctx, m, meta_entity(ctx, meta_struct->entity), (MetaPushStructParameters){ 3631 .layout_style = MetaPushStructStyle_MATLAB, 3632 .union_style = MetaPushStructStyle_MATLAB, 3633 .element_count_style = MetaPushStructStyle_MATLAB, 3634 .base_types = (str8 *)meta_kind_matlab_types, 3635 .suffix = str8(""), 3636 .str_element_prefix = str8(MATLAB_NAMESPACE META_NAMESPACE_UPPER), 3637 .base_type_element_count_scales = (u8 *)meta_kind_elements, 3638 }); 3639 } 3640 } 3641 3642 3643 function void 3644 meta_push_shader_reload_info(MetaprogramContext *m, MetaContext *ctx) 3645 { 3646 if (!ctx->base_shader_count) 3647 return; 3648 3649 /////////////////////////////// 3650 // NOTE(rnp): reloadable infos 3651 meta_begin_scope(m, str8("read_only " META_NAMESPACE_UPPER "ShaderKind " META_NAMESPACE_LOWER "_reloadable_shader_kinds[] = {")); 3652 { 3653 for (da_count shader = 0; shader < ctx->base_shader_count; shader++) { 3654 da_count id = ctx->base_shader_ids[shader]; 3655 meta_push_line(m, str8(META_NAMESPACE_UPPER "ShaderKind_"), ctx->entity_names.data[id], str8(",")); 3656 } 3657 } meta_end_scope(m, str8("};\n")); 3658 3659 meta_begin_scope(m, str8("read_only str8 *" META_NAMESPACE_LOWER "_reloadable_shader_files[] = {")); 3660 { 3661 for (da_count shader = 0; shader < ctx->base_shader_count; shader++) { 3662 da_count id = ctx->base_shader_ids[shader]; 3663 MetaShader *s = &ctx->entities.data[id].shader; 3664 meta_begin_line(m, str8("(str8 []){str8_comp(\""), s->files[0], str8("\")")); 3665 if (s->files[1].length) 3666 meta_push(m, str8(", str8_comp(\""), s->files[1], str8("\")")); 3667 meta_end_line(m, str8("},")); 3668 } 3669 } meta_end_scope(m, str8("};\n")); 3670 3671 meta_begin_scope(m, str8("read_only i32 " META_NAMESPACE_LOWER "_shader_reloadable_index_by_shader[] = {")); 3672 { 3673 for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { 3674 meta_indent(m); 3675 meta_push_i64(m, ctx->base_shader_id_map[shader]); 3676 meta_end_line(m, str8(",")); 3677 } 3678 } meta_end_scope(m, str8("};\n")); 3679 3680 { 3681 u32 info_index = 0; 3682 for (da_count group = 0; group < ctx->entity_kind_counts[MetaEntityKind_ShaderGroup]; group++) { 3683 da_count id = ctx->entity_kind_ids[MetaEntityKind_ShaderGroup][group]; 3684 str8 name = ctx->entity_names.data[id]; 3685 meta_begin_line(m, str8("read_only i32 " META_NAMESPACE_LOWER "_reloadable")); 3686 for (i64 i = 0; i < name.length; i++) { 3687 if IsUpper(name.data[i]) 3688 stream_append_byte(&m->stream, '_'); 3689 stream_append_byte(&m->stream, ToLower(name.data[i])); 3690 } 3691 3692 meta_begin_scope(m, str8("_shader_info_indices[] = {")); { 3693 MetaEntityID child = ctx->entities.data[id].first_child; 3694 do { 3695 /* TODO(rnp): store base shader list in a better format */ 3696 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 3697 if (ctx->base_shader_ids[bs] == child.value) { 3698 meta_indent(m); 3699 meta_push_u64(m, info_index++); 3700 meta_end_line(m, str8(",")); 3701 break; 3702 } 3703 } 3704 child = ctx->entities.data[child.value].next_sibling; 3705 } while (child.value != ctx->entities.data[id].first_child.value); 3706 } meta_end_scope(m, str8("};\n")); 3707 } 3708 } 3709 3710 //////////////////////////////////// 3711 // NOTE(rnp): shader header strings 3712 Temp scratch; 3713 DeferLoop(scratch = temp_begin(m->scratch), temp_end(scratch)) 3714 DeferLoop(meta_begin_scope(m, str8("read_only str8 " META_NAMESPACE_LOWER 3715 "_shader_global_header_strings[] = {")), 3716 meta_end_scope(m, str8("};\n"))) 3717 { 3718 for (da_count ref = 0; ref < ctx->shader_entity_references.count; ref++) { 3719 da_count entity_id = ctx->shader_entity_references.data[ref]; 3720 str8 entity_name = ctx->entity_names.data[entity_id]; 3721 MetaEntity *e = ctx->entities.data + entity_id; 3722 3723 switch (e->kind) { 3724 3725 case MetaEntityKind_Constant:{ 3726 meta_begin_line(m, str8("str8_comp(\"#define "), entity_name, str8(" (")); 3727 switch(e->constant.kind) { 3728 case MetaConstantKind_Integer:{ meta_push_u64(m, e->constant.U64); }break; 3729 case MetaConstantKind_Float:{ meta_push_f64(m, e->constant.F64); }break; 3730 InvalidDefaultCase; 3731 } 3732 meta_end_line(m, str8(")\\n\\n\"),")); 3733 }break; 3734 3735 case MetaEntityKind_Struct:{ 3736 meta_push_line(m, str8("str8_comp(\"\"")); 3737 meta_push_line(m, str8("\"struct "), entity_name, str8(" {\\n\"")); 3738 meta_push_struct_body(ctx, m, e, (MetaPushStructParameters){ 3739 .layout_style = MetaPushStructStyle_C, 3740 .union_style = MetaPushStructStyle_C, 3741 .element_count_style = MetaPushStructStyle_C, 3742 .base_types = (str8 *)meta_kind_glsl_types, 3743 .prefix = str8("\" "), 3744 .suffix = str8(";\\n\""), 3745 }); 3746 meta_push_line(m, str8("\"};\\n\"")); 3747 meta_push_line(m, str8("\"layout(std430, buffer_reference) buffer "), entity_name, str8("Reference {\\n\"")); 3748 meta_push_struct_body(ctx, m, e, (MetaPushStructParameters){ 3749 .layout_style = MetaPushStructStyle_C, 3750 .union_style = MetaPushStructStyle_C, 3751 .element_count_style = MetaPushStructStyle_C, 3752 .base_types = (str8 *)meta_kind_glsl_types, 3753 .prefix = str8("\" "), 3754 .suffix = str8(";\\n\""), 3755 }); 3756 meta_push_line(m, str8("\"};\\n\"")); 3757 meta_push_line(m, str8("\"\\n\"),")); 3758 }break; 3759 3760 case MetaEntityKind_PushConstants:{ 3761 meta_push_line(m, str8("str8_comp(\"\"")); 3762 meta_push_line(m, str8("\"layout(push_constant, std430) uniform PushConstants {\\n\"")); 3763 meta_push_struct_body(ctx, m, e, (MetaPushStructParameters){ 3764 .layout_style = MetaPushStructStyle_C, 3765 .union_style = MetaPushStructStyle_C, 3766 .element_count_style = MetaPushStructStyle_C, 3767 .base_types = (str8 *)meta_kind_glsl_types, 3768 .prefix = str8("\" "), 3769 .suffix = str8(";\\n\""), 3770 }); 3771 meta_push_line(m, str8("\"};\\n\"")); 3772 meta_push_line(m, str8("\"\\n\"),")); 3773 }break; 3774 3775 case MetaEntityKind_Flags:{ 3776 meta_push_line(m, str8("str8_comp(\"\"")); 3777 metagen_push_counted_enum_body(m, str8(""), str8("\"#define "), str8("((CompileFlags & (1 << "), 3778 str8(")) != 0)\\n\""), e->table.entries[0], e->table.entry_count); 3779 meta_push_line(m, str8("\"\\n\"),")); 3780 }break; 3781 3782 case MetaEntityKind_Enumeration:{ 3783 str8 kind_name = push_str8_from_parts(m->scratch, str8(""), entity_name, str8("_")); 3784 meta_push_line(m, str8("str8_comp(\"\"")); 3785 metagen_push_counted_enum_body(m, kind_name, str8("\"#define "), str8(""), str8("\\n\""), 3786 e->table.entries[0], e->table.entry_count); 3787 meta_push_line(m, str8("\"\\n\"),")); 3788 }break; 3789 3790 InvalidDefaultCase; 3791 } 3792 } 3793 } 3794 3795 meta_begin_scope(m, str8("read_only b8 " META_NAMESPACE_LOWER "_shader_has_primitive[] = {")); 3796 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 3797 MetaShader *s = &ctx->entities.data[ctx->base_shader_ids[bs]].shader; 3798 meta_push_line(m, s->kind == MetaShaderKind_Render ? str8("1,") : str8("0,")); 3799 } 3800 meta_end_scope(m, str8("};\n")); 3801 3802 meta_begin_scope(m, str8("read_only b8 " META_NAMESPACE_LOWER "_shader_primitive_is_vertex[] = {")); 3803 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 3804 MetaShader *s = &ctx->entities.data[ctx->base_shader_ids[bs]].shader; 3805 b8 vertex = s->kind == MetaShaderKind_Render && s->render.kind == MetaShaderPrimitiveKind_Vertex; 3806 meta_push_line(m, vertex ? str8("1,") : str8("0,")); 3807 } 3808 meta_end_scope(m, str8("};\n")); 3809 } 3810 3811 function void 3812 meta_push_shader_bake(MetaprogramContext *m, MetaContext *ctx) 3813 { 3814 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 3815 MetaShader *s = &ctx->entities.data[ctx->base_shader_ids[bs]].shader; 3816 3817 str8 shader_name = ctx->entity_names.data[ctx->base_shader_ids[bs]]; 3818 3819 for EachElement(s->files, it) { 3820 if (s->files[it].length > 0) { 3821 meta_begin_line(m, str8("read_only u8 " META_NAMESPACE_LOWER "_shader_")); 3822 for (i64 i = 0; i < shader_name.length; i++) 3823 stream_append_byte(&m->stream, ToLower(shader_name.data[i])); 3824 3825 if (s->kind == MetaShaderKind_Render) 3826 meta_push(m, it == 0 ? str8("_primitive") : str8("_fragment")); 3827 3828 Temp scratch; 3829 DeferLoop(meta_begin_scope(m, str8("_bytes[] = {")), meta_end_scope(m, str8("};\n"))) 3830 DeferLoop(scratch = temp_begin(m->scratch), temp_end(scratch)) 3831 { 3832 str8 filename = push_str8_from_parts(m->scratch, str8(OS_PATH_SEPARATOR), str8("shaders"), s->files[it]); 3833 str8 file = os_read_entire_file(m->scratch, (c8 *)filename.data); 3834 metagen_push_byte_array(m, file); 3835 } 3836 } 3837 } 3838 } 3839 3840 meta_begin_scope(m, str8("read_only str8 *" META_NAMESPACE_LOWER "_shader_data[] = {")); { 3841 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 3842 MetaShader *s = &ctx->entities.data[ctx->base_shader_ids[bs]].shader; 3843 3844 str8 shader_name = ctx->entity_names.data[ctx->base_shader_ids[bs]]; 3845 3846 if (s->kind == MetaShaderKind_Render) { 3847 meta_begin_scope(m, str8("(str8 []){")); 3848 meta_indent(m); 3849 } else { 3850 meta_begin_line(m, str8("(str8 []){")); 3851 } 3852 3853 meta_push(m, str8("{.data = (u8 *)" META_NAMESPACE_LOWER "_shader_")); 3854 for (i64 i = 0; i < shader_name.length; i++) 3855 stream_append_byte(&m->stream, ToLower(shader_name.data[i])); 3856 3857 if (s->kind == MetaShaderKind_Render) 3858 meta_push(m, str8("_primitive")); 3859 3860 meta_push(m, str8("_bytes, .length = countof(" META_NAMESPACE_LOWER "_shader_")); 3861 for (i64 i = 0; i < shader_name.length; i++) 3862 stream_append_byte(&m->stream, ToLower(shader_name.data[i])); 3863 3864 if (s->kind == MetaShaderKind_Render) 3865 meta_push(m, str8("_primitive")); 3866 meta_push(m, str8("_bytes)}")); 3867 3868 if (s->kind == MetaShaderKind_Render) { 3869 meta_end_line(m, str8(",")); 3870 meta_begin_line(m, str8("{.data = (u8 *)" META_NAMESPACE_LOWER "_shader_")); 3871 for (i64 i = 0; i < shader_name.length; i++) 3872 stream_append_byte(&m->stream, ToLower(shader_name.data[i])); 3873 3874 meta_push(m, str8("_fragment_bytes, .length = countof(" META_NAMESPACE_LOWER "_shader_")); 3875 for (i64 i = 0; i < shader_name.length; i++) 3876 stream_append_byte(&m->stream, ToLower(shader_name.data[i])); 3877 meta_end_line(m, str8("_fragment_bytes)}")); 3878 } 3879 3880 if (s->kind == MetaShaderKind_Render) meta_end_scope(m, str8("},")); 3881 else meta_end_line(m, str8("},")); 3882 } 3883 } meta_end_scope(m, str8("};\n")); 3884 } 3885 3886 function void 3887 metagen_emit_c_str8_list(MetaprogramContext *m, str8 *strs, u32 count) 3888 { 3889 meta_begin_scope(m, str8("(str8 []){")); 3890 for (u32 index = 0; index < count; index++) 3891 meta_push_line(m, str8("str8_comp(\""), strs[index], str8("\"),")); 3892 meta_end_scope(m, str8("},")); 3893 } 3894 3895 function b32 3896 metagen_emit_c_code(MetaContext *ctx, Arena *arena) 3897 { 3898 b32 result = 1; 3899 char *out, *out_shaders; 3900 { 3901 str8 basename; 3902 str8_split(ctx->filename, &basename, 0, '.'); 3903 3904 Stream sb = arena_stream(arena); 3905 stream_append_str8s(&sb, ctx->directory, str8(OS_PATH_SEPARATOR), str8("generated")); 3906 stream_append_byte(&sb, 0); 3907 os_make_directory((c8 *)sb.data); 3908 stream_reset(&sb, sb.widx - 1); 3909 3910 stream_append_str8s(&sb, str8(OS_PATH_SEPARATOR), basename, str8(".c")); 3911 stream_append_byte(&sb, 0); 3912 3913 out = (c8 *)arena_stream_commit_and_reset(arena, &sb).data; 3914 3915 stream_append_str8s(&sb, ctx->directory, str8(OS_PATH_SEPARATOR), str8("generated")); 3916 stream_append_str8s(&sb, str8(OS_PATH_SEPARATOR), basename, str8("_shader_data.c")); 3917 stream_append_byte(&sb, 0); 3918 3919 out_shaders = (c8 *)arena_stream_commit_zero(arena, &sb).data; 3920 } 3921 3922 MetaprogramContext m[1] = {{.stream = arena_stream(arena), .scratch = ctx->scratch}}; 3923 3924 arena_clear(m->scratch); 3925 3926 if (setjmp(compiler_jmp_buf)) { 3927 build_fatal("Failed to generate C Code"); 3928 } 3929 3930 //////////////////////////// 3931 // NOTE(rnp): shader baking 3932 if (ctx->base_shader_count) { 3933 char **deps = push_array(m->scratch, char *, 2 * ctx->base_shader_count); 3934 u32 dep_count = 0; 3935 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 3936 MetaShader *s = &ctx->entities.data[ctx->base_shader_ids[bs]].shader; 3937 deps[dep_count++] = (c8 *)push_str8_from_parts(m->scratch, str8(OS_PATH_SEPARATOR), 3938 str8("shaders"), s->files[0]).data; 3939 if (s->files[1].length > 0) 3940 deps[dep_count++] = (c8 *)push_str8_from_parts(m->scratch, str8(OS_PATH_SEPARATOR), 3941 str8("shaders"), s->files[1]).data; 3942 } 3943 3944 if (needs_rebuild_(out_shaders, deps, dep_count)) { 3945 build_log_generate("%.*s: baking shaders", (i32)ctx->filename.length, ctx->filename.data); 3946 meta_push(m, c_file_header); 3947 meta_push_shader_bake(m, ctx); 3948 result &= meta_write_and_reset(m, out_shaders); 3949 } 3950 } 3951 3952 arena_clear(m->scratch); 3953 3954 { 3955 CommandList deps = meta_extract_emit_file_dependencies(ctx, m->scratch); 3956 *da_push(m->scratch, &deps) = (c8 *)ctx->fullpath.data; 3957 if (!needs_rebuild_(out, deps.data, deps.count)) 3958 return result; 3959 } 3960 3961 arena_clear(m->scratch); 3962 3963 build_log_generate("%.*s: C Code", (i32)ctx->filename.length, ctx->filename.data); 3964 3965 meta_push(m, c_file_header); 3966 3967 ///////////////////////// 3968 // NOTE(rnp): constants 3969 { 3970 u32 integers = 0; 3971 u32 floats = 0; 3972 3973 for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { 3974 da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; 3975 MetaEntity *e = ctx->entities.data + id; 3976 if (e->constant.kind == MetaConstantKind_Integer) integers++; 3977 if (e->constant.kind == MetaConstantKind_Float) floats++; 3978 } 3979 3980 u32 row_alloc_count = Max(integers, floats); 3981 str8 *columns[2]; 3982 columns[0] = push_array(m->scratch, str8, row_alloc_count); 3983 columns[1] = push_array(m->scratch, str8, row_alloc_count); 3984 3985 u32 row_count; 3986 3987 row_count = 0; 3988 if (integers) meta_push_line(m, str8("// NOTE: Constants (Integer)")); 3989 for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { 3990 da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; 3991 MetaEntity *e = ctx->entities.data + id; 3992 if (e->constant.kind == MetaConstantKind_Integer) { 3993 Stream sb = arena_stream(m->scratch); 3994 stream_append_str8(&sb, str8("(")); 3995 stream_append_u64(&sb, e->constant.U64); 3996 columns[0][row_count] = ctx->entity_names.data[id]; 3997 columns[1][row_count] = arena_stream_commit(m->scratch, &sb); 3998 row_count++; 3999 } 4000 } 4001 metagen_push_table(m, str8("#define " META_NAMESPACE_UPPER), str8(")"), columns, row_count, 2); 4002 4003 row_count = 0; 4004 if (floats) meta_push_line(m, str8("\n// NOTE: Constants (Float)")); 4005 for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { 4006 da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; 4007 MetaEntity *e = ctx->entities.data + id; 4008 if (e->constant.kind == MetaConstantKind_Float) { 4009 Stream sb = arena_stream(m->scratch); 4010 stream_append_str8(&sb, str8("(")); 4011 stream_append_f64(&sb, e->constant.F64, 1000000); 4012 columns[0][row_count] = ctx->entity_names.data[id]; 4013 columns[1][row_count] = arena_stream_commit(m->scratch, &sb); 4014 row_count++; 4015 } 4016 } 4017 metagen_push_table(m, str8("#define " META_NAMESPACE_UPPER), str8(")"), columns, row_count, 2); 4018 4019 if (integers || floats) meta_push(m, str8("\n")); 4020 } 4021 4022 arena_clear(m->scratch); 4023 4024 ///////////////////////// 4025 // NOTE(rnp): enumerants 4026 struct {MetaEntityKind kind; b32 flags;} enums[] = { 4027 {MetaEntityKind_Enumeration, 0}, 4028 {MetaEntityKind_Flags, 1}, 4029 }; 4030 for EachElement(enums, it) { 4031 for (da_count kind = 0; kind < ctx->entity_kind_counts[enums[it].kind]; kind++) { 4032 da_count id = ctx->entity_kind_ids[enums[it].kind][kind]; 4033 MetaEntity *e = ctx->entities.data + id; 4034 4035 str8 enum_name = push_str8_from_parts(m->scratch, str8(""), str8(META_NAMESPACE_UPPER), 4036 ctx->entity_names.data[id]); 4037 metagen_push_c_enum(m, enum_name, enums[it].flags, e->table.entries[0], e->table.entry_count); 4038 } 4039 } 4040 4041 arena_clear(m->scratch); 4042 4043 // TODO(rnp): technically this needs to be namespaced to the file they are coming from 4044 if (ctx->entity_kind_counts[MetaEntityKind_Shader]) { 4045 str8 kind = str8(META_NAMESPACE_UPPER "ShaderKind"); 4046 str8 kind_full = str8(META_NAMESPACE_UPPER "ShaderKind_"); 4047 meta_begin_scope(m, str8("typedef enum {")); 4048 metagen_push_counted_enum_body_from_ids(m, kind_full, str8(""), str8("= "), str8(","), 4049 ctx->entity_kind_ids[MetaEntityKind_Shader], ctx->entity_names.data, 4050 ctx->entity_kind_counts[MetaEntityKind_Shader]); 4051 meta_push_line(m, kind_full, str8("Count,\n")); 4052 4053 str8 *columns[2]; 4054 columns[0] = push_array(m->scratch, str8, ctx->entity_kind_counts[MetaEntityKind_ShaderGroup] * 3); 4055 columns[1] = push_array(m->scratch, str8, ctx->entity_kind_counts[MetaEntityKind_ShaderGroup] * 3); 4056 4057 u32 rows = 0; 4058 for (da_count group = 0; group < ctx->entity_kind_counts[MetaEntityKind_ShaderGroup]; group++) { 4059 da_count id = ctx->entity_kind_ids[MetaEntityKind_ShaderGroup][group]; 4060 MetaEntityID child = ctx->entities.data[id].first_child; 4061 str8 name = ctx->entity_names.data[id]; 4062 4063 da_count shader_count = meta_entity_children_count(ctx, (MetaEntityID){.value = id}); 4064 4065 if (child.value != 0) { 4066 // NOTE(rnp): childen pushed in LIFO order 4067 str8 first_name = ctx->entity_names.data[ctx->entities.data[child.value].previous_sibling.value]; 4068 str8 last_name = ctx->entity_names.data[child.value]; 4069 4070 columns[0][3 * group + 0] = push_str8_from_parts(m->scratch, str8(""), kind, str8("_"), name, str8("First")); 4071 columns[1][3 * group + 0] = push_str8_from_parts(m->scratch, str8(""), str8("= "), kind, str8("_"), first_name); 4072 4073 columns[0][3 * group + 1] = push_str8_from_parts(m->scratch, str8(""), kind, str8("_"), name, str8("Last")); 4074 columns[1][3 * group + 1] = push_str8_from_parts(m->scratch, str8(""),str8("= "), kind, str8("_"), last_name); 4075 4076 columns[0][3 * group + 2] = push_str8_from_parts(m->scratch, str8(""), kind, str8("_"), name, str8("Count")); 4077 Stream sb = arena_stream(m->scratch); 4078 stream_append_str8(&sb, str8("= ")); 4079 stream_append_i64(&sb, shader_count); 4080 columns[1][3 * group + 2] = arena_stream_commit(m->scratch, &sb); 4081 4082 rows += 3; 4083 } 4084 } 4085 metagen_push_table(m, str8(""), str8(","), columns, rows, 2); 4086 4087 meta_end_scope(m, str8("} "), kind, str8(";\n")); 4088 } 4089 4090 arena_clear(m->scratch); 4091 4092 ////////////////////// 4093 // NOTE(rnp): structs 4094 { 4095 for EachElement(meta_struct_entity_kinds, kind_it) { 4096 if (meta_struct_emit[kind_it]) { 4097 for (da_count it = 0; it < ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; it++) { 4098 da_count entity = ctx->entity_kind_ids[meta_struct_entity_kinds[kind_it]][it]; 4099 4100 meta_begin_scope(m, str8("typedef struct {")); { 4101 meta_push_struct_body(ctx, m, ctx->entities.data + entity, (MetaPushStructParameters){ 4102 .layout_style = MetaPushStructStyle_C, 4103 .union_style = MetaPushStructStyle_C, 4104 .element_count_style = MetaPushStructStyle_C, 4105 .base_types = (str8 *)meta_kind_c_types, 4106 .suffix = str8(";"), 4107 .str_element_prefix = str8(META_NAMESPACE_UPPER), 4108 }); 4109 } meta_end_scope(m, str8("} " META_NAMESPACE_UPPER), ctx->entity_names.data[entity], str8(";")); 4110 meta_push(m, str8("\n")); 4111 } 4112 } 4113 } 4114 } 4115 4116 // NOTE: shader bake parameter union 4117 if (ctx->entity_kind_counts[MetaEntityKind_BakeParameters]) 4118 DeferLoop(meta_begin_scope(m, str8("typedef union {")), 4119 meta_end_scope(m, str8("} " META_NAMESPACE_UPPER "ShaderBakeParameters;\n"))) 4120 { 4121 str8 *columns[2]; 4122 columns[0] = push_array(m->scratch, str8, ctx->entity_kind_counts[MetaEntityKind_BakeParameters]); 4123 columns[1] = push_array(m->scratch, str8, ctx->entity_kind_counts[MetaEntityKind_BakeParameters]); 4124 4125 for (da_count bake = 0; bake < ctx->entity_kind_counts[MetaEntityKind_BakeParameters]; bake++) { 4126 da_count id = ctx->entity_kind_ids[MetaEntityKind_BakeParameters][bake]; 4127 4128 str8 bake_name = ctx->entity_names.data[id]; 4129 str8 shader_name = {.data = bake_name.data, .length = bake_name.length - str8("BakeParameters").length}; 4130 4131 columns[0][bake] = push_str8_from_parts(m->scratch, str8(""), str8(META_NAMESPACE_UPPER), bake_name); 4132 columns[1][bake] = shader_name; 4133 } 4134 metagen_push_table(m, str8(""), str8(";"), columns, 4135 ctx->entity_kind_counts[MetaEntityKind_BakeParameters], 2); 4136 4137 arena_clear(m->scratch); 4138 } 4139 4140 // TODO(rnp): we may want this to include more than just the bake structs 4141 if (ctx->base_shader_count) 4142 DeferLoop(meta_begin_scope(m, str8("typedef enum {")), 4143 meta_end_scope(m, str8("} " META_NAMESPACE_UPPER "StructKind;\n"))) 4144 { 4145 str8 kind_full = str8(META_NAMESPACE_UPPER "StructKind_"); 4146 metagen_push_counted_enum_body_from_ids(m, kind_full, str8(""), str8("= "), str8(","), 4147 ctx->entity_kind_ids[MetaEntityKind_BakeParameters], 4148 ctx->entity_names.data, 4149 ctx->entity_kind_counts[MetaEntityKind_BakeParameters]); 4150 meta_push_line(m, kind_full, str8("Count,")); 4151 } 4152 4153 // TODO(rnp): we may want this to include more than just the bake structs 4154 if (ctx->base_shader_count) 4155 DeferLoop(meta_begin_scope(m, str8("read_only MetaStructMember *meta_struct_members_by_id[] = {")), 4156 meta_end_scope(m, str8("};\n"))) 4157 { 4158 for EachIndex((u64)ctx->entity_kind_counts[MetaEntityKind_BakeParameters], id) { 4159 MetaTable *t = &ctx->entities.data[ctx->entity_kind_ids[MetaEntityKind_BakeParameters][id]].table; 4160 MetaStruct *s = ctx->struct_infos + t->struct_info_id; 4161 4162 str8 *columns[4]; 4163 for EachElement(columns, it) 4164 columns[it] = push_array(m->scratch, str8, s->info.member_count); 4165 4166 u32 offset = 0; 4167 for EachIndex((u64)s->info.member_count, member) { 4168 // TODO(rnp): for now we only handle bake structs which must only have base types 4169 assert((s->member_flags[member] & MetaStructMemberFlag_ReferenceType) == 0); 4170 4171 Stream sb = arena_stream(m->scratch); 4172 stream_append_u64(&sb, s->type_ids[member]); stream_append_byte(&sb, ','); 4173 columns[0][member] = arena_stream_commit_and_reset(m->scratch, &sb); 4174 4175 stream_append_u64(&sb, offset); stream_append_byte(&sb, ','); 4176 columns[1][member] = arena_stream_commit_and_reset(m->scratch, &sb); 4177 4178 stream_append_u64(&sb, s->elements[member]); stream_append_byte(&sb, ','); 4179 columns[2][member] = arena_stream_commit_and_reset(m->scratch, &sb); 4180 4181 columns[3][member] = str8("0"); // TODO(rnp): reference type flag 4182 4183 offset += meta_kind_byte_sizes[s->type_ids[member]]; 4184 } 4185 4186 DeferLoop(meta_begin_scope(m, str8("(MetaStructMember []){")), meta_end_scope(m, str8("},"))) 4187 metagen_push_table(m, str8("{"), str8("},"), columns, s->info.member_count, countof(columns)); 4188 4189 arena_clear(m->scratch); 4190 } 4191 } 4192 4193 if (ctx->base_shader_count) 4194 DeferLoop(meta_begin_scope(m, str8("read_only str8 *meta_struct_member_names_by_id[] = {")), 4195 meta_end_scope(m, str8("};\n"))) 4196 { 4197 for EachIndex((u64)ctx->entity_kind_counts[MetaEntityKind_BakeParameters], id) { 4198 MetaTable *t = &ctx->entities.data[ctx->entity_kind_ids[MetaEntityKind_BakeParameters][id]].table; 4199 MetaStruct *s = ctx->struct_infos + t->struct_info_id; 4200 4201 DeferLoop(meta_begin_scope(m, str8("(str8 []){")), meta_end_scope(m, str8("},"))) 4202 for EachIndex((u64)s->info.member_count, member) 4203 meta_push_line(m, str8("str8_comp(\""), s->members[member], str8("\"),")); 4204 } 4205 } 4206 4207 if (ctx->base_shader_count) 4208 DeferLoop(meta_begin_scope(m, str8("read_only MetaStructInfo meta_struct_info_by_id[] = {")), 4209 meta_end_scope(m, str8("};\n"))) 4210 { 4211 str8 *columns[4]; 4212 for EachElement(columns, it) 4213 columns[it] = push_array(m->scratch, str8, ctx->entity_kind_counts[MetaEntityKind_BakeParameters]); 4214 4215 for EachIndex((u64)ctx->entity_kind_counts[MetaEntityKind_BakeParameters], id) { 4216 da_count entity = ctx->entity_kind_ids[MetaEntityKind_BakeParameters][id]; 4217 MetaTable *t = &ctx->entities.data[entity].table; 4218 MetaStruct *s = ctx->struct_infos + t->struct_info_id; 4219 4220 columns[0][id] = push_str8_from_parts(m->scratch, str8(""), ctx->entity_names.data[entity], str8("\"),")); 4221 4222 Stream sb = arena_stream(m->scratch); 4223 stream_append_u64(&sb, s->info.member_count); stream_append_byte(&sb, ','); 4224 columns[1][id] = arena_stream_commit_and_reset(m->scratch, &sb); 4225 4226 stream_append_u64(&sb, s->info.size); stream_append_byte(&sb, ','); 4227 columns[2][id] = arena_stream_commit_and_reset(m->scratch, &sb); 4228 4229 columns[3][id] = str8("0"); // TODO(rnp): union flags 4230 } 4231 4232 metagen_push_table(m, str8("{str8_comp(\""), str8("},"), columns, 4233 ctx->entity_kind_counts[MetaEntityKind_BakeParameters], countof(columns)); 4234 4235 arena_clear(m->scratch); 4236 } 4237 4238 ///////////////////////////////// 4239 // NOTE(rnp): shader info tables 4240 if (ctx->entity_kind_counts[MetaEntityKind_Shader]) 4241 DeferLoop(meta_begin_scope(m, str8("read_only str8 " META_NAMESPACE_LOWER "_shader_names[] = {")), 4242 meta_end_scope(m, str8("};\n"))) 4243 { 4244 for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { 4245 da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; 4246 meta_push_line(m, str8("str8_comp(\""), ctx->entity_names.data[id], str8("\"),")); 4247 } 4248 } 4249 4250 meta_push_shader_reload_info(m, ctx); 4251 4252 if (ctx->base_shader_count) 4253 DeferLoop(meta_begin_scope(m, str8("read_only i32 *" META_NAMESPACE_LOWER "_shader_header_vectors[] = {")), 4254 meta_end_scope(m, str8("};\n"))) 4255 { 4256 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 4257 da_count id = ctx->base_shader_ids[bs]; 4258 MetaShader *s = &ctx->entities.data[id].shader; 4259 if (s->entity_reference_ids.count) { 4260 meta_begin_line(m, str8("(i32 []){")); 4261 for (da_count ref_id = 0; ref_id < s->entity_reference_ids.count; ref_id++) { 4262 if (ref_id != 0) meta_push(m, str8(", ")); 4263 MetaEntityReference *r = &ctx->entities.data[s->entity_reference_ids.data[ref_id]].reference; 4264 meta_push_i64(m, meta_lookup_id_slow(ctx->shader_entity_references.data, 4265 ctx->shader_entity_references.count, 4266 r->resolved_id.value)); 4267 } 4268 meta_end_line(m, str8("},")); 4269 } else { 4270 meta_push_line(m, str8("0,")); 4271 } 4272 } 4273 } 4274 4275 if (ctx->base_shader_count) 4276 DeferLoop(meta_begin_scope(m, str8("read_only i32 " META_NAMESPACE_LOWER "_shader_header_vector_lengths[] = {")), 4277 meta_end_scope(m, str8("};\n"))) 4278 { 4279 for (da_count bs= 0; bs < ctx->base_shader_count; bs++) { 4280 da_count id = ctx->base_shader_ids[bs]; 4281 MetaShader *s = &ctx->entities.data[id].shader; 4282 meta_indent(m); 4283 meta_push_i64(m, s->entity_reference_ids.count); 4284 meta_end_line(m, str8(",")); 4285 } 4286 } 4287 4288 if (ctx->base_shader_count) 4289 DeferLoop(meta_begin_scope(m, str8("read_only str8 *" META_NAMESPACE_LOWER "_shader_compile_flag_names[] = {")), 4290 meta_end_scope(m, str8("};\n"))) 4291 { 4292 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 4293 da_count id = ctx->base_shader_ids[bs]; 4294 MetaEntity *e = ctx->entities.data + id; 4295 MetaEntityID fid = meta_entity_first_child_of_kind(ctx, e, MetaEntityKind_Flags); 4296 if (fid.value != 0) { 4297 MetaEntity *flags = meta_entity(ctx, fid); 4298 metagen_emit_c_str8_list(m, flags->table.entries[MetaStructField_Name], flags->table.entry_count); 4299 } else { 4300 meta_push_line(m, str8("0,")); 4301 } 4302 } 4303 } 4304 4305 if (ctx->base_shader_count) 4306 DeferLoop(meta_begin_scope(m, str8("read_only u8 " META_NAMESPACE_LOWER "_shader_compile_flag_counts[] = {")), 4307 meta_end_scope(m, str8("};\n"))) 4308 { 4309 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 4310 da_count id = ctx->base_shader_ids[bs]; 4311 MetaEntity *e = ctx->entities.data + id; 4312 MetaEntityID fid = meta_entity_first_child_of_kind(ctx, e, MetaEntityKind_Flags); 4313 meta_indent(m); 4314 meta_push_u64(m, ctx->entities.data[fid.value].table.entry_count); 4315 meta_end_line(m, str8(",")); 4316 } 4317 } 4318 4319 if (ctx->base_shader_count) 4320 DeferLoop(meta_begin_scope(m, str8("read_only i32 " 4321 META_NAMESPACE_LOWER "_base_shader_to_bake_struct_id[] = {")), 4322 meta_end_scope(m, str8("};\n"))) 4323 { 4324 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 4325 da_count id = ctx->base_shader_ids[bs]; 4326 MetaEntity *e = ctx->entities.data + id; 4327 MetaEntityID bp_id = meta_entity_first_child_of_kind(ctx, e, MetaEntityKind_BakeParameters); 4328 i64 index = meta_lookup_id_slow(ctx->entity_kind_ids[MetaEntityKind_BakeParameters], 4329 ctx->entity_kind_counts[MetaEntityKind_BakeParameters], 4330 bp_id.value); 4331 meta_indent(m); meta_push_i64(m, index); meta_end_line(m, str8(",")); 4332 } 4333 } 4334 4335 if (ctx->base_shader_count) 4336 DeferLoop(meta_begin_scope(m, str8("read_only u8 " META_NAMESPACE_LOWER "_shader_push_constant_sizes[] = {")), 4337 meta_end_scope(m, str8("};\n"))) 4338 { 4339 for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { 4340 da_count id = ctx->base_shader_ids[bs]; 4341 MetaEntity *e = ctx->entities.data + id; 4342 MetaEntityID pc_id = meta_entity_first_child_of_kind(ctx, e, MetaEntityKind_PushConstants); 4343 if (pc_id.value != 0) { 4344 meta_push_line(m, str8("sizeof(" META_NAMESPACE_UPPER), ctx->entity_names.data[id], str8("PushConstants),")); 4345 } else { 4346 meta_push_line(m, str8("0,")); 4347 } 4348 } 4349 } 4350 4351 metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_C, meta_kind_c_types); 4352 4353 result = meta_write_and_reset(m, out); 4354 4355 arena_clear(m->scratch); 4356 4357 return result; 4358 } 4359 4360 function b32 4361 metagen_matlab_union(MetaprogramContext *m, MetaContext *ctx, MetaStruct *u, str8 outdir, str8 namespace) 4362 { 4363 b32 result = 1; 4364 4365 Temp scratch; 4366 DeferLoop(scratch = temp_begin(m->scratch), temp_end(scratch)) 4367 { 4368 str8 outfile = push_str8_from_parts(m->scratch, str8(OS_PATH_SEPARATOR), outdir, str8("Base.m")); 4369 meta_begin_scope(m, str8("classdef Base")); 4370 { 4371 meta_begin_scope(m, str8("properties (Constant)")); 4372 { 4373 meta_begin_line(m, str8("byteSize(1,1) uint32 = ")); 4374 meta_push_u64(m, u->info.size); 4375 meta_end_line(m); 4376 } meta_end_scope(m, str8("end")); 4377 } meta_end_scope(m, str8("end")); 4378 result &= meta_end_and_write_matlab(m, (c8 *)outfile.data); 4379 } 4380 4381 for EachIndex(u->info.member_count, union_member) { 4382 if ((u->member_flags[union_member] & MetaStructMemberFlag_ReferenceType) == 0) { 4383 str8 type_name = meta_kind_c_types[u->type_ids[union_member]]; 4384 str8 name = u->members[union_member]; 4385 build_log_failure("%.*s:%u:%u: error: base type in MATLAB union:\n" 4386 "%.*s %.*s\n" 4387 "MATLAB unions only support Struct and Union members\n", 4388 (i32)ctx->filename.length, ctx->filename.data, u->location.line, u->location.column, 4389 (i32)name.length, name.data, (i32)type_name.length, type_name.data); 4390 result = 0; 4391 break; 4392 } 4393 4394 DeferLoop(scratch = temp_begin(m->scratch), temp_end(scratch)) 4395 { 4396 MetaStruct *s = ctx->struct_infos + ctx->entities.data[u->type_ids[union_member]].table.struct_info_id; 4397 str8 sub_name = u->members[union_member]; 4398 str8 outfile = push_str8_from_parts(m->scratch, str8(""), outdir, str8(OS_PATH_SEPARATOR), sub_name, str8(".m")); 4399 DeferLoop(meta_begin_scope(m, str8("classdef "), sub_name, str8(" < " MATLAB_NAMESPACE META_NAMESPACE_UPPER), 4400 namespace, str8(".Base")), 4401 meta_end_scope(m, str8("end"))) 4402 { 4403 meta_push_matlab_properties(m, ctx, s); 4404 4405 meta_push(m, str8("\n")); 4406 4407 DeferLoop(meta_begin_scope(m, str8("methods")), meta_end_scope(m, str8("end"))) 4408 { 4409 DeferLoop(meta_begin_scope(m, str8("function bytes = toBytes(obj)")), 4410 meta_end_scope(m, str8("end"))) 4411 { 4412 meta_begin_scope(m, str8("arguments (Output)")); 4413 { 4414 meta_push_line(m, str8("bytes uint8")); 4415 } meta_end_scope(m, str8("end")); 4416 meta_push_line(m, str8("bytes = zeros(1, obj.byteSize, 'uint8');")); 4417 4418 str8 *columns[3]; 4419 columns[0] = push_array(m->scratch, str8, s->info.member_count); 4420 columns[1] = push_array(m->scratch, str8, s->info.member_count); 4421 columns[2] = push_array(m->scratch, str8, s->info.member_count); 4422 4423 u32 offset = 1; 4424 for EachIndex(s->info.member_count, member) { 4425 Stream sb = arena_stream(m->scratch); 4426 4427 i32 type_id = s->type_ids[member]; 4428 4429 u32 member_size = 0; 4430 if (s->member_flags[member] & MetaStructMemberFlag_ReferenceType) { 4431 MetaStruct *ref = ctx->struct_infos + ctx->entities.data[type_id].table.struct_info_id; 4432 member_size = ref->info.size; 4433 // TODO(rnp): arrays of structs 4434 // - calculate member count with element count multiplied in for struct members 4435 // - do a sub loop for struct arrays calling toBytes method on each struct array element 4436 if (meta_struct_member_elements(ctx, s, member) != 1) { 4437 str8 name = s->members[member]; 4438 build_log_failure("%.*s:%u:%u: error: array of structs present in struct referenced by MATLAB union:\n" 4439 "%.*s %.*s\n" 4440 "MATLAB unions do not currently support array of structs\n", 4441 (i32)ctx->filename.length, ctx->filename.data, u->location.line, u->location.column, 4442 (i32)name.length, name.data, (i32)ref->info.name.length, ref->info.name.data); 4443 } 4444 } else { 4445 member_size = meta_kind_byte_sizes[type_id]; 4446 } 4447 4448 stream_append_u64(&sb, offset); 4449 stream_append_byte(&sb, ':'); 4450 stream_append_u64(&sb, offset - 1 + member_size); 4451 stream_append_byte(&sb, ')'); 4452 offset += member_size; 4453 4454 columns[0][member] = arena_stream_commit_and_reset(m->scratch, &sb); 4455 4456 stream_append_str8s(&sb, str8("= typecast(obj."), s->members[member]); 4457 if (s->member_flags[member] & MetaStructMemberFlag_ReferenceType) { 4458 // TODO(rnp): arrays of structs 4459 // - calculate member count with element count multiplied in for struct members 4460 // - do a sub loop for struct arrays calling toBytes method on each struct array element 4461 // lookup subtype, if union replace with byte array, else reference sub type 4462 MetaStruct *ref = ctx->struct_infos + ctx->entities.data[type_id].table.struct_info_id; 4463 if ((ref->info.flags & MetaStructFlag_Union) == 0) { 4464 stream_append_str8(&sb, str8(".toBytes()")); 4465 } 4466 } else { 4467 stream_append_str8(&sb, str8("(:)")); 4468 } 4469 stream_append_byte(&sb, ','); 4470 4471 columns[1][member] = arena_stream_commit_and_reset(m->scratch, &sb); 4472 columns[2][member] = str8("'uint8');"); 4473 } 4474 4475 metagen_push_table(m, str8("bytes("), str8(""), columns, s->info.member_count, 3); 4476 } 4477 } 4478 } 4479 result &= meta_end_and_write_matlab(m, (c8 *)outfile.data); 4480 } 4481 } 4482 4483 return result; 4484 } 4485 4486 function b32 4487 metagen_emit_matlab_code(MetaContext *ctx, Arena *arena) 4488 { 4489 b32 result = 1; 4490 if (!needs_rebuild(OUTPUT("matlab/OGLBeamformerShaderStage.m"), "beamformer.meta")) 4491 return result; 4492 4493 build_log_generate("MATLAB Bindings"); 4494 char *base_directory = OUTPUT("matlab"); 4495 if (!os_remove_directory(base_directory)) 4496 build_fatal("failed to remove directory: %s", base_directory); 4497 4498 if (setjmp(compiler_jmp_buf)) { 4499 os_remove_directory(base_directory); 4500 build_log_error("Failed to generate MATLAB Bindings"); 4501 return 0; 4502 } 4503 4504 os_make_directory(base_directory); 4505 4506 MetaprogramContext m[1] = {{.stream = arena_stream(arena), .scratch = ctx->scratch}}; 4507 4508 arena_clear(m->scratch); 4509 4510 meta_begin_matlab_class(m, "OGLBeamformerShaderStage", "int32"); 4511 meta_begin_scope(m, str8("enumeration")); 4512 { 4513 da_count group_id = -1; 4514 for (da_count group = 0; group < ctx->entity_kind_counts[MetaEntityKind_ShaderGroup]; group++) { 4515 da_count id = ctx->entity_kind_ids[MetaEntityKind_ShaderGroup][group]; 4516 str8 group_name = ctx->entity_names.data[id]; 4517 if (str8_equal(group_name, str8("Compute"))) { 4518 group_id = id; 4519 break; 4520 } 4521 } 4522 if (group_id != -1) { 4523 da_count children; 4524 da_count *ids = meta_entity_extract_children(ctx, (MetaEntityID){.value = group_id}, 4525 &children, m->scratch); 4526 if (children > 0) { 4527 metagen_push_counted_enum_body_from_ids(m, str8(""), str8(""), str8("("), str8(")"), ids, 4528 ctx->entity_names.data, children); 4529 } 4530 arena_clear(m->scratch); 4531 } else { 4532 build_log_failure("failed to find Compute shader group in meta info\n"); 4533 } 4534 result &= group_id != -1; 4535 } 4536 result &= meta_end_and_write_matlab(m, OUTPUT("matlab/OGLBeamformerShaderStage.m")); 4537 4538 for (da_count kind = 0; kind < ctx->entity_kind_counts[MetaEntityKind_Enumeration]; kind++) { 4539 da_count id = ctx->entity_kind_ids[MetaEntityKind_Enumeration][kind]; 4540 str8 name = ctx->entity_names.data[id]; 4541 str8 output = push_str8_from_parts(m->scratch, str8(""), str8(OUTPUT("matlab/OGLBeamformer")), name, str8(".m")); 4542 4543 MetaTable *etable = &ctx->entities.data[id].table; 4544 str8 *kinds = etable->entries[0]; 4545 meta_begin_scope(m, str8("classdef OGLBeamformer"), name, str8(" < int32")); 4546 meta_begin_scope(m, str8("enumeration")); 4547 str8 prefix = str8(""); 4548 if (etable->entry_count > 0 && IsDigit(kinds[0].data[0])) prefix = str8("m"); 4549 metagen_push_counted_enum_body(m, str8(""), prefix, str8("("), str8(")"), kinds, etable->entry_count); 4550 result &= meta_end_and_write_matlab(m, (c8 *)output.data); 4551 4552 arena_clear(m->scratch); 4553 } 4554 4555 //////////////////// 4556 // NOTE: emit files 4557 { 4558 MetaEmitOperationListSet *emit_set = ctx->emit_sets + MetaEmitLang_MATLAB; 4559 for (da_count list = 0; list < emit_set->count; list++) { 4560 MetaEmitOperationList *ops = emit_set->data + list; 4561 str8 output = push_str8_from_parts(m->scratch, str8(""), 4562 str8(OUTPUT("matlab") OS_PATH_SEPARATOR "OGLBeamformer"), 4563 ops->filename, str8(".m")); 4564 meta_push_line(m, str8("% GENERATED CODE")); 4565 metagen_run_emit(m, ctx, ops, meta_kind_matlab_types); 4566 result &= meta_write_and_reset(m, (c8 *)output.data); 4567 4568 arena_clear(m->scratch); 4569 } 4570 } 4571 4572 ///////////////////////// 4573 // NOTE(rnp): entities marked @MATLAB 4574 { 4575 da_count children; 4576 da_count *ids = meta_entity_extract_children(ctx, ctx->matlab_entity, &children, m->scratch); 4577 4578 for EachIndex((u64)children, it) { 4579 MetaEntity *rr = ctx->entities.data + ids[it]; 4580 da_count ref_id = ctx->entities.data[rr->reference.resolved_id.value].reference.resolved_id.value; 4581 MetaEntity *re = ctx->entities.data + ref_id; 4582 4583 switch (re->kind) { 4584 InvalidDefaultCase; 4585 case MetaEntityKind_Union:{ 4586 Temp scratch; 4587 DeferLoop(scratch = temp_begin(m->scratch), temp_end(scratch)) 4588 { 4589 MetaStruct *s = ctx->struct_infos + re->table.struct_info_id; 4590 str8 name = (rr->reference.scope_name.length > 0) ? rr->reference.scope_name : s->info.name; 4591 str8 outdir = push_str8_from_parts(m->scratch, str8(""), str8(OUTPUT("matlab") OS_PATH_SEPARATOR), 4592 str8("+" MATLAB_NAMESPACE META_NAMESPACE_UPPER), name); 4593 os_make_directory((c8 *)outdir.data); 4594 result &= metagen_matlab_union(m, ctx, s, outdir, name); 4595 } 4596 }break; 4597 4598 case MetaEntityKind_Struct:{ 4599 MetaStruct *s = ctx->struct_infos + re->table.struct_info_id; 4600 str8 name = (rr->reference.scope_name.length > 0) ? rr->reference.scope_name : s->info.name; 4601 str8 outfile = push_str8_from_parts(m->scratch, str8(""), str8(OUTPUT("matlab") OS_PATH_SEPARATOR), 4602 str8(MATLAB_NAMESPACE META_NAMESPACE_UPPER), name, str8(".m")); 4603 meta_begin_scope(m, str8("classdef " MATLAB_NAMESPACE META_NAMESPACE_UPPER), name); 4604 { 4605 meta_push_matlab_properties(m, ctx, s); 4606 } meta_end_scope(m, str8("end")); 4607 result &= meta_end_and_write_matlab(m, (c8 *)outfile.data); 4608 }break; 4609 4610 } 4611 } 4612 } 4613 4614 arena_clear(m->scratch); 4615 4616 return result; 4617 } 4618 4619 function void 4620 meta_push_helper_library_header_base(MetaprogramContext *m, MetaContext *ctx) 4621 { 4622 meta_push(m, c_file_header); 4623 meta_push_line(m, str8("#include <stdint.h>\n")); 4624 4625 ///////////////////////// 4626 // NOTE(rnp): Constants 4627 { 4628 u32 integers = 0; 4629 for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { 4630 da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; 4631 MetaEntity *e = ctx->entities.data + id; 4632 if (e->constant.kind == MetaConstantKind_Integer) integers++; 4633 } 4634 4635 str8 *columns[2]; 4636 columns[0] = push_array(m->scratch, str8, integers); 4637 columns[1] = push_array(m->scratch, str8, integers); 4638 4639 u32 row_count = 0; 4640 meta_push_line(m, str8("// NOTE: Constants (Integer)")); 4641 for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { 4642 da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; 4643 MetaEntity *e = ctx->entities.data + id; 4644 if (e->constant.kind == MetaConstantKind_Integer) { 4645 Stream sb = arena_stream(m->scratch); 4646 stream_append_str8(&sb, str8("(")); 4647 stream_append_u64(&sb, e->constant.U64); 4648 columns[0][row_count] = ctx->entity_names.data[id]; 4649 columns[1][row_count] = arena_stream_commit(m->scratch, &sb); 4650 row_count++; 4651 } 4652 } 4653 metagen_push_table(m, str8("#define " META_NAMESPACE_UPPER), str8(")"), columns, row_count, 2); 4654 meta_push(m, str8("\n")); 4655 } 4656 4657 arena_clear(m->scratch); 4658 4659 ///////////////////////// 4660 // NOTE(rnp): enumerants 4661 for (da_count kind = 0; kind < ctx->entity_kind_counts[MetaEntityKind_Enumeration]; kind++) { 4662 da_count id = ctx->entity_kind_ids[MetaEntityKind_Enumeration][kind]; 4663 MetaEntity *e = ctx->entities.data + id; 4664 4665 str8 enum_name = push_str8_from_parts(m->scratch, str8(""), str8(META_NAMESPACE_UPPER), 4666 ctx->entity_names.data[id]); 4667 metagen_push_c_enum(m, enum_name, 0, e->table.entries[0], e->table.entry_count); 4668 4669 arena_clear(m->scratch); 4670 } 4671 4672 { 4673 da_count group_id = -1; 4674 for (da_count group = 0; group < ctx->entity_kind_counts[MetaEntityKind_ShaderGroup]; group++) { 4675 da_count id = ctx->entity_kind_ids[MetaEntityKind_ShaderGroup][group]; 4676 str8 group_name = ctx->entity_names.data[id]; 4677 if (str8_equal(group_name, str8("Compute"))) { 4678 group_id = id; 4679 break; 4680 } 4681 } 4682 4683 if (group_id != -1) { 4684 da_count children; 4685 da_count *ids = meta_entity_extract_children(ctx, (MetaEntityID){.value = group_id}, 4686 &children, m->scratch); 4687 if (children > 0) { 4688 str8 kind = str8(META_NAMESPACE_UPPER "ShaderKind"); 4689 str8 kind_full = str8(META_NAMESPACE_UPPER "ShaderKind_"); 4690 meta_begin_scope(m, str8("typedef enum {")); 4691 { 4692 metagen_push_counted_enum_body_from_ids(m, kind_full, str8(""), str8("= "), str8(","), ids, 4693 ctx->entity_names.data, children); 4694 meta_push_line(m, kind_full, str8("Count,")); 4695 } meta_end_scope(m, str8("} "), kind, str8(";\n")); 4696 4697 meta_begin_line(m, str8("#define "), kind_full, str8("ComputeCount (")); 4698 meta_push_i64(m, children); 4699 meta_end_line(m, str8(")\n")); 4700 } 4701 4702 arena_clear(m->scratch); 4703 } else { 4704 build_log_failure("failed to find Compute shader group in meta info\n"); 4705 } 4706 } 4707 } 4708 4709 function void 4710 meta_entity_resolve_references(MetaContext *ctx, da_count *ids, u64 id_count) 4711 { 4712 for EachIndex(id_count, it) { 4713 MetaEntity *e = meta_entity(ctx, (MetaEntityID){ids[it]}); 4714 switch (e->kind) { 4715 InvalidDefaultCase; 4716 case MetaEntityKind_ReferenceReference:{ 4717 MetaEntity *r = meta_entity(ctx, e->reference.resolved_id); 4718 ids[it] = r->reference.resolved_id.value; 4719 }break; 4720 } 4721 } 4722 } 4723 4724 function b32 4725 metagen_emit_helper_library_header(MetaContext *ctx, Arena *arena) 4726 { 4727 b32 result = 1; 4728 char *out = OUTPUT("ogl_beamformer_lib.h"); 4729 if (!needs_rebuild(out, "lib/ogl_beamformer_lib_base.h", "beamformer.meta")) 4730 return result; 4731 4732 build_log_generate("Library Header"); 4733 4734 str8 base_header = os_read_entire_file(arena, "lib/ogl_beamformer_lib_base.h"); 4735 4736 MetaprogramContext m[1] = {{.stream = arena_stream(arena), .scratch = ctx->scratch}}; 4737 4738 meta_push_helper_library_header_base(m, ctx); 4739 4740 arena_clear(m->scratch); 4741 ///////////////////////// 4742 // NOTE(rnp): entities marked @Library 4743 { 4744 da_count children; 4745 da_count *ids = meta_entity_extract_children(ctx, ctx->library_entity, &children, m->scratch); 4746 4747 meta_entity_resolve_references(ctx, ids, children); 4748 4749 for EachIndex((u64)children, it) { 4750 MetaEntity *e = ctx->entities.data + ids[it]; 4751 switch (e->kind) { 4752 InvalidDefaultCase; 4753 4754 case MetaEntityKind_Struct:{ 4755 meta_begin_scope(m, str8("typedef struct {")); { 4756 meta_push_struct_body(ctx, m, e, (MetaPushStructParameters){ 4757 .layout_style = MetaPushStructStyle_C, 4758 .union_style = MetaPushStructStyle_C, 4759 .element_count_style = MetaPushStructStyle_C, 4760 .base_types = (str8 *)meta_kind_base_c_types, 4761 .suffix = str8(";"), 4762 .str_element_prefix = str8(META_NAMESPACE_UPPER), 4763 .base_type_element_count_scales = (u8 *)meta_kind_elements, 4764 }); 4765 } meta_end_scope(m, str8("} " META_NAMESPACE_UPPER), ctx->entity_names.data[ids[it]], str8(";\n")); 4766 }break; 4767 4768 case MetaEntityKind_Union:{}break; 4769 4770 } 4771 } 4772 4773 arena_clear(m->scratch); 4774 } 4775 4776 metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_CLibrary, meta_kind_base_c_types); 4777 4778 meta_push_line(m, str8("// END GENERATED CODE\n")); 4779 4780 meta_push(m, base_header); 4781 result &= meta_write_and_reset(m, out); 4782 4783 // NOTE(rnp): matlab compatible header 4784 { 4785 meta_push_helper_library_header_base(m, ctx); 4786 ///////////////////////// 4787 // NOTE(rnp): entities marked @Library 4788 { 4789 da_count children; 4790 da_count *ids = meta_entity_extract_children(ctx, ctx->library_entity, &children, m->scratch); 4791 4792 meta_entity_resolve_references(ctx, ids, children); 4793 4794 for EachIndex((u64)children, it) { 4795 MetaEntity *e = ctx->entities.data + ids[it]; 4796 switch (e->kind) { 4797 InvalidDefaultCase; 4798 case MetaEntityKind_Struct:{ 4799 meta_begin_scope(m, str8("typedef struct {")); 4800 { 4801 meta_push_struct_body(ctx, m, e, (MetaPushStructParameters){ 4802 .layout_style = MetaPushStructStyle_C, 4803 .union_style = MetaPushStructStyle_MATLAB, 4804 .element_count_style = MetaPushStructStyle_C, 4805 .base_types = (str8 *)meta_kind_base_c_types, 4806 .suffix = str8(";"), 4807 .str_element_prefix = str8(META_NAMESPACE_UPPER), 4808 .base_type_element_count_scales = (u8 *)meta_kind_elements, 4809 }); 4810 } meta_end_scope(m, str8("} " META_NAMESPACE_UPPER), ctx->entity_names.data[ids[it]], str8(";\n")); 4811 }break; 4812 case MetaEntityKind_Union:{}break; 4813 } 4814 } 4815 } 4816 4817 arena_clear(m->scratch); 4818 4819 metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_CLibrary, meta_kind_base_c_types); 4820 4821 meta_push_line(m, str8("// END GENERATED CODE\n")); 4822 4823 meta_push(m, base_header); 4824 result &= meta_write_and_reset(m, OUTPUT("ogl_beamformer_lib_matlab.h")); 4825 } 4826 4827 CommandList cpp = {0}; 4828 cmd_append(m->scratch, &cpp, PREPROCESSOR, out, COMPILER_OUTPUT, OUTPUT("ogl_beamformer_lib_python_ffi.h")); 4829 result &= run_synchronous(m->scratch, &cpp); 4830 4831 arena_clear(m->scratch); 4832 4833 return result; 4834 } 4835 4836 function MetaContext * 4837 metagen_load_context(Arena *arena, char *filename) 4838 { 4839 if (setjmp(compiler_jmp_buf)) { 4840 /* NOTE(rnp): compiler error */ 4841 return 0; 4842 } 4843 4844 MetaContext *ctx = push_struct(arena, MetaContext); 4845 ctx->scratch = arena_create(.commit_size = MB(1)); 4846 ctx->arena = arena; 4847 4848 // NOTE(rnp): nil entity 4849 *da_push(ctx->arena, &ctx->entity_names) = str8("Nil"); 4850 da_push(ctx->arena, &ctx->entities); 4851 4852 MetaContext *result = ctx; 4853 4854 ctx->filename = push_str8(ctx->arena, str8_from_c_str(filename)); 4855 ctx->directory = str8_chop(&ctx->filename, str8_scan_backwards(ctx->filename, OS_PATH_SEPARATOR_CHAR)); 4856 ctx->fullpath = str8_from_c_str((c8 *)ctx->directory.data); 4857 if (ctx->directory.length > 0) str8_chop(&ctx->filename, 1); 4858 if (ctx->directory.length <= 0) { 4859 ctx->directory = str8("."); 4860 ctx->fullpath = push_str8_from_parts(ctx->arena, str8(""), ctx->directory, 4861 str8(OS_PATH_SEPARATOR), ctx->filename); 4862 } 4863 4864 MetaEntryStack entries = meta_entry_stack_from_file(ctx->arena, filename); 4865 4866 for (i64 i = 0; i < entries.count; i++) { 4867 MetaEntry *e = entries.data + i; 4868 4869 switch (e->kind) { 4870 case MetaEntryKind_Constant:{ 4871 meta_pack_constant(ctx, e); 4872 }break; 4873 4874 case MetaEntryKind_Emit:{ 4875 i += meta_pack_emit(ctx, e, entries.count - i); 4876 }break; 4877 4878 case MetaEntryKind_Embed:{ 4879 meta_embed(ctx, e, entries.count - i); 4880 }break; 4881 4882 case MetaEntryKind_Expand:{ 4883 i += meta_expand(ctx, e, entries.count - i, 0); 4884 }break; 4885 4886 case MetaEntryKind_Library: 4887 case MetaEntryKind_MATLAB: 4888 { 4889 if (e->kind == MetaEntryKind_Library && ctx->library_entity.value == 0) { 4890 ctx->library_entity = meta_intern_entity(ctx, str8("LibraryEntity"), MetaEntityKind_List, 4891 meta_root_entity_id(ctx), (MetaLocation){0}, 0); 4892 } 4893 4894 if (e->kind == MetaEntryKind_MATLAB && ctx->matlab_entity.value == 0) { 4895 ctx->matlab_entity = meta_intern_entity(ctx, str8("MATLABEntity"), MetaEntityKind_List, 4896 meta_root_entity_id(ctx), (MetaLocation){0}, 0); 4897 } 4898 4899 MetaEntityID parent = e->kind == MetaEntryKind_Library ? ctx->library_entity : ctx->matlab_entity; 4900 str8 prefix = e->kind == MetaEntryKind_Library ? str8("Library") : str8("MATLAB"); 4901 str8 scope_name = str8(""); 4902 if (e->argument_count > 0) 4903 scope_name = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; 4904 i += meta_pack_references(ctx, e, entries.count - i, parent, scope_name, prefix); 4905 }break; 4906 4907 case MetaEntryKind_ShaderGroup:{ 4908 i += meta_pack_shader_group(ctx, e, entries.count - i); 4909 }break; 4910 4911 case MetaEntryKind_Enumeration: 4912 case MetaEntryKind_Flags: 4913 case MetaEntryKind_Struct: 4914 case MetaEntryKind_Table: 4915 case MetaEntryKind_Union: 4916 { 4917 i += meta_pack_table_entity(ctx, e, entries.count - i, e->name, meta_root_entity_id(ctx)); 4918 }break; 4919 4920 default: 4921 { 4922 meta_entry_error(e, "invalid @%s() in global scope\n", meta_entry_kind_strings[e->kind]); 4923 }break; 4924 } 4925 } 4926 4927 // NOTE(rnp): sort enitity ids into sub arrays 4928 { 4929 assert(ctx->entity_kind_counts[MetaEntityKind_Nil] == 0); 4930 4931 for EachNonZeroEnumValue(MetaEntityKind, it) { 4932 if (ctx->entity_kind_counts[it]) { 4933 ctx->entity_kind_ids[it] = push_array(ctx->arena, typeof(*ctx->entity_kind_ids[it]), ctx->entity_kind_counts[it]); 4934 } 4935 } 4936 4937 da_count entity_counts[MetaEntityKind_Count] = {0}; 4938 for (da_count entity = 1; entity < ctx->entities.count; entity++) { 4939 MetaEntity *e = ctx->entities.data + entity; 4940 da_count index = entity_counts[e->kind]++; 4941 ctx->entity_kind_ids[e->kind][index] = da_index(e, &ctx->entities); 4942 } 4943 } 4944 4945 // NOTE(rnp): resolve reference entities 4946 { 4947 for (da_count entity = 0; entity < ctx->entity_kind_counts[MetaEntityKind_Reference]; entity++) { 4948 MetaEntity *e = ctx->entities.data + ctx->entity_kind_ids[MetaEntityKind_Reference][entity]; 4949 da_count reference_id = meta_lookup_string_slow(ctx->entity_names.data, ctx->entity_names.count, e->reference.reference_name); 4950 if (reference_id >= 0) 4951 e->reference.resolved_id.value = reference_id; 4952 } 4953 4954 b32 error = 0; 4955 for (da_count entity = 0; entity < ctx->entity_kind_counts[MetaEntityKind_Reference]; entity++) { 4956 MetaEntity *e = ctx->entities.data + ctx->entity_kind_ids[MetaEntityKind_Reference][entity]; 4957 MetaEntityReference *r = &e->reference; 4958 if (e->reference.resolved_id.value == 0) { 4959 meta_compiler_error_message(e->location, "undefined reference%s to '%.*s'\n", 4960 r->reference_count > 1? "s" : "", 4961 (i32)r->reference_name.length, r->reference_name.data); 4962 if (r->reference_count > 1) 4963 meta_compiler_message(" referenced in %d other places\n", r->reference_count - 1); 4964 error = 1; 4965 } 4966 } 4967 if (error) meta_error(); 4968 } 4969 4970 // NOTE(rnp): extract entities referenced by shaders 4971 { 4972 for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { 4973 da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; 4974 MetaShader *s = &ctx->entities.data[id].shader; 4975 for (da_count ref = 0; ref < s->entity_reference_ids.count; ref++) { 4976 MetaEntityReference *r = &ctx->entities.data[s->entity_reference_ids.data[ref]].reference; 4977 meta_intern_id(ctx, &ctx->shader_entity_references, r->resolved_id.value); 4978 } 4979 } 4980 } 4981 4982 // NOTE(rnp): finalize struct info 4983 { 4984 da_count struct_infos_count = 0; 4985 for EachElement(meta_struct_entity_kinds, kind_it) 4986 struct_infos_count += ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; 4987 4988 ctx->struct_infos_count = struct_infos_count; 4989 ctx->struct_infos = push_array(ctx->arena, MetaStruct, struct_infos_count); 4990 4991 da_count struct_info_index = 0; 4992 for EachElement(meta_struct_entity_kinds, kind_it) { 4993 for (da_count it = 0; it < ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; it++) { 4994 da_count entity = ctx->entity_kind_ids[meta_struct_entity_kinds[kind_it]][it]; 4995 MetaEntity *e = ctx->entities.data + entity; 4996 e->table.struct_info_id = struct_info_index++; 4997 4998 MetaStruct *s = ctx->struct_infos + e->table.struct_info_id; 4999 s->info.name = ctx->entity_names.data[entity]; 5000 s->info.member_count = e->table.entry_count; 5001 s->info.size = (u32)-1; 5002 s->members = e->table.entries[MetaStructField_Name]; 5003 s->location = e->location; 5004 s->entity = (MetaEntityID){entity}; 5005 if (meta_struct_entity_kinds[kind_it] == MetaEntityKind_Union) 5006 s->info.flags = MetaStructFlag_Union; 5007 5008 s->member_flags = push_array(ctx->arena, MetaBuildStructMemberFlags, s->info.member_count); 5009 s->elements = push_array_no_zero(ctx->arena, i32, s->info.member_count); 5010 s->type_ids = push_array_no_zero(ctx->arena, i32, s->info.member_count); 5011 memory_clear(s->type_ids, -1, sizeof(*s->type_ids) * s->info.member_count); 5012 memory_clear(s->elements, -1, sizeof(*s->elements) * s->info.member_count); 5013 } 5014 } 5015 5016 // NOTE(rnp): resolve types 5017 for EachElement(meta_struct_entity_kinds, kind_it) { 5018 for (da_count it = 0; it < ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; it++) { 5019 da_count entity = ctx->entity_kind_ids[meta_struct_entity_kinds[kind_it]][it]; 5020 MetaEntity *e = ctx->entities.data + entity; 5021 MetaStruct *s = ctx->struct_infos + e->table.struct_info_id; 5022 5023 str8 *types = e->table.entries[MetaStructField_Type]; 5024 for EachIndex(s->info.member_count, member) { 5025 s->type_ids[member] = meta_lookup_string_slow(meta_kind_meta_types, MetaKind_Count, types[member]); 5026 5027 if (s->type_ids[member] == -1 && meta_struct_allow_references[kind_it]) { 5028 s->member_flags[member] = MetaBuildStructMemberFlag_ReferenceType; 5029 i64 id = meta_lookup_string_slow(ctx->entity_names.data, ctx->entity_names.count, types[member]); 5030 if (id >= 0) { 5031 MetaEntityKind kind = ctx->entities.data[id].kind; 5032 if (!meta_entity_kind_struct_reference_target[kind]) { 5033 meta_compiler_error(e->location, "struct '%.*s' references entity '%.*s' which is not a valid struct member\n", 5034 (i32)s->info.name.length, s->info.name.data, (i32)types[member].length, types[member].data); 5035 } 5036 if (ctx->entities.data[id].kind == MetaEntityKind_Union) 5037 s->info.flags |= MetaStructFlag_ContainsUnion; 5038 s->type_ids[member] = id; 5039 } 5040 } 5041 5042 if (s->type_ids[member] == -1) { 5043 meta_compiler_error(e->location, "struct '%.*s' references undefined type '%.*s'\n", 5044 (i32)s->info.name.length, s->info.name.data, (i32)types[member].length, types[member].data); 5045 } 5046 } 5047 } 5048 } 5049 5050 // NOTE(rnp): resolve element counts 5051 for EachElement(meta_struct_entity_kinds, kind_it) { 5052 for (da_count it = 0; it < ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; it++) { 5053 da_count entity = ctx->entity_kind_ids[meta_struct_entity_kinds[kind_it]][it]; 5054 MetaEntity *e = ctx->entities.data + entity; 5055 MetaStruct *s = ctx->struct_infos + e->table.struct_info_id; 5056 5057 str8 *elements = e->table.entries[MetaStructField_Elements]; 5058 for EachIndex(s->info.member_count, member) { 5059 NumberConversion integer = integer_from_str8(elements[member]); 5060 if (integer.result == NumberConversionResult_Success) { 5061 s->elements[member] = integer.U64; 5062 } else { 5063 str8 ref_name = elements[member]; 5064 if (ref_name.data[0] == '#') { 5065 s->member_flags[member] |= MetaBuildStructMemberFlag_EnumerationCount; 5066 str8_chop(&ref_name, 1); 5067 } else { 5068 s->member_flags[member] |= MetaBuildStructMemberFlag_ReferenceElements; 5069 } 5070 5071 i64 id = meta_lookup_string_slow(ctx->entity_names.data, ctx->entity_names.count, ref_name); 5072 if (id >= 0) { 5073 MetaEntity *ee = ctx->entities.data + id; 5074 b32 valid = ee->kind == MetaEntityKind_Enumeration || 5075 (ee->kind == MetaEntityKind_Constant && ee->constant.kind == MetaConstantKind_Integer); 5076 if (!valid) { 5077 // TODO(rnp): point at correct member 5078 meta_compiler_error(e->location, "struct '%.*s': element count for field '%.*s'" 5079 "references '%.*s' which is not an integer constant\n", 5080 (i32)s->info.name.length, s->info.name.data, 5081 (i32)s->members[member].length, s->members[member].data, 5082 (i32)elements[member].length, elements[member].data); 5083 } 5084 s->elements[member] = id; 5085 } 5086 } 5087 5088 if (s->elements[member] == 0) 5089 s->info.flags |= MetaStructFlag_ContainsPointer; 5090 5091 if (s->elements[member] == -1) { 5092 meta_compiler_error(e->location, "struct '%.*s': element count for field '%.*s' could not be determined\n", 5093 (i32)s->info.name.length, s->info.name.data, 5094 (i32)s->members[member].length, s->members[member].data); 5095 } 5096 } 5097 } 5098 } 5099 5100 // NOTE(rnp): resolve size 5101 // TODO(rnp): depth could be predetermined 5102 b32 all_done = 0; 5103 for (u32 iterations = 0; !all_done && iterations < 16; iterations++) { 5104 for EachIndex(ctx->struct_infos_count, structure) { 5105 MetaStruct *s = ctx->struct_infos + structure; 5106 u32 size = 0; 5107 b32 is_union = (s->info.flags & MetaStructFlag_Union) != 0; 5108 for EachIndex(s->info.member_count, member) { 5109 b32 type_reference = (s->member_flags[member] & MetaStructMemberFlag_ReferenceType) != 0; 5110 u32 elements = meta_struct_member_elements(ctx, s, member); 5111 5112 u32 member_size = 0; 5113 if (type_reference) { 5114 MetaEntity *ref = ctx->entities.data + s->type_ids[member]; 5115 if (ref->kind == MetaEntityKind_Enumeration || ref->kind == MetaEntityKind_Flags) { 5116 i64 limit = ref->kind == MetaEntityKind_Flags ? 32 : U32_MAX; 5117 if (ref->table.entry_count < limit) member_size = sizeof(u32); 5118 else member_size = sizeof(u64); 5119 } else { 5120 MetaStruct *sub_struct = ctx->struct_infos + ref->table.struct_info_id; 5121 if (sub_struct->info.size != (u32)-1) { 5122 member_size = elements ? sub_struct->info.size * elements : 8; 5123 } else { 5124 size = (u32)-1; 5125 break; 5126 } 5127 } 5128 } else { 5129 member_size = elements ? meta_kind_byte_sizes[s->type_ids[member]] * elements : 8; 5130 } 5131 size = is_union ? Max(size, member_size) : size + member_size; 5132 } 5133 if (size != (u32)-1) 5134 s->info.size = size; 5135 } 5136 5137 all_done = 1; 5138 for EachIndex(ctx->struct_infos_count, structure) 5139 all_done &= ctx->struct_infos[structure].info.size != (u32)-1; 5140 } 5141 5142 if (!all_done) { 5143 for EachIndex(ctx->struct_infos_count, structure) { 5144 MetaStruct *s = ctx->struct_infos + structure; 5145 if (s->info.size == (u32)-1) { 5146 meta_compiler_error(s->location, "storage size for struct '%.*s' could not be determined\n", 5147 (i32)s->info.name.length, s->info.name.data); 5148 } 5149 } 5150 } 5151 } 5152 5153 // NOTE(rnp): finalize base shader nonsense 5154 { 5155 for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { 5156 MetaEntity *e = ctx->entities.data + ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; 5157 if (e->shader.files[0].length > 0) 5158 ctx->base_shader_count++; 5159 } 5160 5161 ctx->base_shader_ids = push_array(ctx->arena, da_count, ctx->base_shader_count); 5162 ctx->base_shader_id_map = push_array(ctx->arena, da_count, ctx->entity_kind_counts[MetaEntityKind_Shader]); 5163 5164 da_count base_shader_ids_index = 0; 5165 for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { 5166 da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; 5167 if (ctx->entities.data[id].shader.files[0].length > 0) 5168 ctx->base_shader_ids[base_shader_ids_index++] = id; 5169 } 5170 5171 // NOTE(rnp): first pass to resolve real shaders 5172 for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { 5173 da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; 5174 if (ctx->entities.data[id].shader.files[0].length > 0) { 5175 ctx->base_shader_id_map[shader] = meta_lookup_id_slow(ctx->base_shader_ids, 5176 ctx->base_shader_count, 5177 id); 5178 } else { 5179 ctx->base_shader_id_map[shader] = -1; 5180 } 5181 } 5182 5183 // NOTE(rnp): second pass to resolve aliases 5184 for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { 5185 da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; 5186 if (ctx->base_shader_id_map[shader] == -1) { 5187 if (ctx->entities.data[id].shader.kind == MetaShaderKind_Alias) { 5188 ctx->base_shader_id_map[shader] = meta_lookup_id_slow(ctx->base_shader_ids, 5189 ctx->base_shader_count, 5190 ctx->entities.data[id].shader.alias_parent_id.value); 5191 assert(ctx->base_shader_id_map[shader] != -1); 5192 } 5193 } 5194 } 5195 } 5196 5197 arena_clear(ctx->scratch); 5198 result->arena = 0; 5199 return result; 5200 } 5201 5202 function b32 5203 metagen_file_direct(Arena *arena, char *filename) 5204 { 5205 MetaContext *ctx = metagen_load_context(arena, filename); 5206 b32 result = ctx && metagen_emit_c_code(ctx, arena); 5207 return result; 5208 } 5209 5210 BASE_IMPORT void 5211 entry_point(i32 argc, char *argv[]) 5212 { 5213 u64 start_time = os_timer_count(); 5214 g_argv0 = argv[0]; 5215 5216 b32 result = 1; 5217 Arena *arena = arena_create(.commit_size = MB(8)); 5218 5219 check_rebuild_self(arena, argc, argv); 5220 arena_clear(arena); 5221 5222 os_make_directory(OUTDIR); 5223 5224 result &= metagen_file_direct(arena, "assets" OS_PATH_SEPARATOR "assets.meta"); 5225 arena_clear(arena); 5226 5227 result &= metagen_file_direct(arena, "beamformer_core.meta"); 5228 arena_clear(arena); 5229 5230 MetaContext *meta = metagen_load_context(arena, "beamformer.meta"); 5231 if (!meta) os_exit(1); 5232 5233 Temp scratch; 5234 DeferLoop(scratch = temp_begin(arena), temp_end(scratch)) 5235 result &= metagen_emit_c_code(meta, arena); 5236 DeferLoop(scratch = temp_begin(arena), temp_end(scratch)) 5237 result &= metagen_emit_helper_library_header(meta, arena); 5238 DeferLoop(scratch = temp_begin(arena), temp_end(scratch)) 5239 result &= metagen_emit_matlab_code(meta, arena); 5240 5241 arena_clear(arena); 5242 5243 parse_config(argc, argv); 5244 5245 if (!build_raylib(arena)) os_exit(1); 5246 if (!build_glslang(arena)) os_exit(1); 5247 5248 ///////////////// 5249 // lib/tests 5250 result &= build_helper_library(arena); 5251 if (config.tests) result &= build_tests(arena); 5252 5253 ////////////////// 5254 // static portion 5255 result &= build_beamformer_main(arena); 5256 5257 ///////////////////////// 5258 // hot reloadable portion 5259 // 5260 // NOTE: this is built after main because on w32 we need to export 5261 // gl function pointers for the reloadable portion to import 5262 if (config.debug) result &= build_beamformer_as_library(arena); 5263 5264 if (config.time) { 5265 f64 seconds = (f64)(os_timer_count() - start_time) / (f64)os_timer_frequency(); 5266 build_log_info("took %0.03f [s]", seconds); 5267 } 5268 5269 os_exit(result != 1); 5270 }