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