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