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