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