Eliminates all 39 mutable static globals across sema.c (37) and intern_pool.c (2). State is now held in properly-typed structs passed as parameters, mirroring the Zig reference implementation layout. New files matching Zig src/ layout: - compilation.h: CompilationConfig + Compilation (matches Compilation.zig) - zcu.h/zcu.c: ZcuFile, ZcuNamespace, Zcu, zcuInit/zcuDeinit (matches Zcu.zig) - zcu_per_thread.h: forward declarations for PerThread-style functions Key changes: - InternPool gains navs[] (dynamically allocated) + nav_count/nav_cap; Nav functions now take InternPool* (was implicit via globals) - Sema gains Zcu* zcu; semaInit now takes Zcu* instead of InternPool* - All module-level state (files, namespaces, memoized state, config) moved from static globals into Zcu struct - zig0.c creates Compilation + Zcu before semaInit - Test files updated to use zcuInit/zcuDeinit API Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
153 lines
4.5 KiB
C
153 lines
4.5 KiB
C
#include "ast.h"
|
|
#include "astgen.h"
|
|
#include "compilation.h"
|
|
#include "intern_pool.h"
|
|
#include "sema.h"
|
|
#include "verbose_air.h"
|
|
#include "verbose_intern_pool.h"
|
|
#include "zcu.h"
|
|
#include "zir.h"
|
|
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
// API:
|
|
// - code = 0: program successfully terminated.
|
|
// - code = 1: panicked, panic message in msg. Caller should free msg.
|
|
// - code = 2: interpreter error, error in msg. Caller should free msg.
|
|
static int zig0Run(const char* program, const char* source_dir,
|
|
const char* module_root, bool verbose_air, bool verbose_intern_pool,
|
|
char** msg) {
|
|
uint32_t len = (uint32_t)strlen(program);
|
|
Ast ast = astParse(program, len);
|
|
if (ast.has_error) {
|
|
*msg = ast.err_msg;
|
|
ast.err_msg = NULL;
|
|
astDeinit(&ast);
|
|
return 2;
|
|
}
|
|
|
|
fprintf(stderr, "tokens: %u, nodes: %u, first token: %s\n", ast.tokens.len,
|
|
ast.nodes.len, tokenizerGetTagString(ast.tokens.tags[0]));
|
|
|
|
Zir zir = astGen(&ast);
|
|
astDeinit(&ast);
|
|
|
|
if (zir.has_compile_errors) {
|
|
const char err[] = "astgen failed";
|
|
*msg = malloc(sizeof(err));
|
|
memcpy(*msg, err, sizeof(err));
|
|
zirDeinit(&zir);
|
|
return 2;
|
|
}
|
|
|
|
fprintf(stderr, "zir: %u instructions, %u extra, %u string bytes\n",
|
|
zir.inst_len, zir.extra_len, zir.string_bytes_len);
|
|
|
|
Compilation comp;
|
|
comp.config.module_root = module_root;
|
|
comp.config.target_cpu_arch = "wasm32";
|
|
comp.config.target_cpu_model = "lime1";
|
|
comp.config.object_format = "wasm";
|
|
comp.config.link_mode = "static";
|
|
comp.config.is_test = false;
|
|
Zcu* zcu = zcuInit(&comp);
|
|
Sema sema;
|
|
semaInit(&sema, zcu, zir);
|
|
sema.source_dir = source_dir;
|
|
SemaFuncAirList func_airs = semaAnalyze(&sema);
|
|
if (verbose_intern_pool)
|
|
verboseIpPrint(stderr, &zcu->ip);
|
|
if (verbose_air)
|
|
verboseAirPrint(stderr, &func_airs, &zcu->ip);
|
|
semaDeinit(&sema);
|
|
semaFuncAirListDeinit(&func_airs);
|
|
zcuDeinit(zcu);
|
|
zirDeinit(&zir);
|
|
return 0;
|
|
}
|
|
|
|
// API: run from file.
|
|
// module_root_override: if non-NULL, use this as module_root instead of
|
|
// auto-deriving from the file path.
|
|
// code = 3: abnormal error, expect something in stderr.
|
|
int zig0RunFile(const char* fname, const char* module_root_override,
|
|
bool verbose_air, bool verbose_intern_pool, char** msg) {
|
|
FILE* f = fopen(fname, "r");
|
|
if (f == NULL) {
|
|
perror("fopen");
|
|
return 3;
|
|
}
|
|
fseek(f, 0, SEEK_END);
|
|
long fsizel = ftell(f);
|
|
if (fsizel == -1) {
|
|
perror("ftell");
|
|
fclose(f);
|
|
return 3;
|
|
}
|
|
unsigned long fsize = (unsigned long)fsizel;
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
char* program = malloc(fsize + 1);
|
|
if (program == NULL) {
|
|
perror("malloc");
|
|
fclose(f);
|
|
return 3;
|
|
}
|
|
|
|
size_t bytes_read = fread(program, 1, fsize, f);
|
|
if (bytes_read < fsize) {
|
|
if (ferror(f)) {
|
|
perror("fread");
|
|
} else {
|
|
fprintf(stderr, "Unexpected end of file\n");
|
|
}
|
|
free(program);
|
|
fclose(f);
|
|
return 3;
|
|
}
|
|
fclose(f);
|
|
program[fsize] = 0;
|
|
|
|
// Compute source_dir (dirname of fname) for import resolution.
|
|
char source_dir[1024] = { 0 };
|
|
{
|
|
const char* last_slash = strrchr(fname, '/');
|
|
if (last_slash) {
|
|
size_t len = (size_t)(last_slash - fname);
|
|
if (len >= sizeof(source_dir))
|
|
len = sizeof(source_dir) - 1;
|
|
memcpy(source_dir, fname, len);
|
|
source_dir[len] = '\0';
|
|
}
|
|
}
|
|
|
|
// Determine module_root: use override if provided, otherwise
|
|
// auto-derive from source_dir by looking for "lib/" prefix.
|
|
const char* module_root = module_root_override;
|
|
char module_root_buf[1024] = { 0 };
|
|
if (!module_root) {
|
|
const char* lib_pos = strstr(source_dir, "/lib/");
|
|
if (lib_pos) {
|
|
size_t len = (size_t)(lib_pos - source_dir);
|
|
if (len >= sizeof(module_root_buf))
|
|
len = sizeof(module_root_buf) - 1;
|
|
memcpy(module_root_buf, source_dir, len);
|
|
module_root_buf[len] = '\0';
|
|
module_root = module_root_buf;
|
|
} else if (strncmp(source_dir, "lib/", 4) == 0
|
|
|| strncmp(source_dir, "lib", 4) == 0) {
|
|
module_root_buf[0] = '.';
|
|
module_root_buf[1] = '\0';
|
|
module_root = module_root_buf;
|
|
}
|
|
}
|
|
|
|
int code = zig0Run(program, source_dir, module_root, verbose_air,
|
|
verbose_intern_pool, msg);
|
|
free(program);
|
|
return code;
|
|
}
|