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