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