mod.c (2597B)
1 #include <assert.h> 2 #include <errno.h> 3 #include <limits.h> 4 #include <stdint.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include "check.h" 9 #include "identifier.h" 10 #include "lex.h" 11 #include "mod.h" 12 #include "parse.h" 13 #include "scope.h" 14 #include "type_store.h" 15 #include "util.h" 16 17 static char * 18 ident_to_env(const struct identifier *ident) 19 { 20 if (ident->ns) { 21 char *ns = ident_to_env(ident->ns); 22 if (!ns) { 23 return NULL; 24 } 25 int n = snprintf(NULL, 0, "%s_%s", ns, ident->name); 26 char *str = xcalloc(1, n + 1); 27 snprintf(str, n + 1, "%s_%s", ns, ident->name); 28 free(ns); 29 return str; 30 } 31 return xstrdup(ident->name); 32 } 33 34 35 static const char * 36 open_typedefs(struct identifier *ident) 37 { 38 char *env = ident_to_env(ident); 39 char versenv[PATH_MAX+1]; 40 snprintf(versenv, sizeof(versenv), "HARE_VERSION_%s", env); 41 42 char *version = getenv(versenv); 43 if (!version) { 44 version = env; 45 } else { 46 version = xstrdup(version); 47 free(env); 48 } 49 50 const struct pathspec paths[] = { 51 {.var = "HARECACHE", .path = "/%s/%s.td"}, 52 {.var = "XDG_CACHE_HOME", .path = "/hare/%s/%s.td"}, 53 {.var = "HOME", .path = "/.cache/hare/%s/%s.td"} 54 }; 55 char *pathfmt = getpath(paths, sizeof(paths) / sizeof(paths[0])); 56 assert(pathfmt); 57 58 static char path[PATH_MAX+1]; 59 const char *ipath = ident_to_path(ident); 60 snprintf(path, sizeof(path), pathfmt, ipath, version); 61 free(version); 62 return path; 63 } 64 65 struct scope * 66 module_resolve(struct modcache *cache[], 67 struct ast_global_decl *defines, 68 struct identifier *ident, 69 struct type_store *store) 70 { 71 uint32_t hash = identifier_hash(FNV1A_INIT, ident); 72 struct modcache **bucket = &cache[hash % MODCACHE_BUCKETS]; 73 for (; *bucket; bucket = &(*bucket)->next) { 74 if (identifier_eq(&(*bucket)->ident, ident)) { 75 return (*bucket)->scope; 76 } 77 } 78 79 struct lexer lexer = {0}; 80 struct ast_unit aunit = {0}; 81 82 const char *path = open_typedefs(ident); 83 FILE *f = fopen(path, "r"); 84 if (!f) { 85 fprintf(stderr, "Could not open module '%s' for reading from %s: %s\n", 86 identifier_unparse(ident), path, 87 strerror(errno)); 88 exit(EXIT_FAILURE); 89 } 90 91 const char *old = sources[0]; 92 sources[0] = path; 93 lex_init(&lexer, f, 0); 94 parse(&lexer, &aunit.subunits); 95 lex_finish(&lexer); 96 97 // TODO: Free unused bits 98 struct unit u = {0}; 99 struct scope *scope = check_internal(store, 100 cache, NULL, defines, &aunit, &u, true); 101 102 sources[0] = old; 103 bucket = &cache[hash % MODCACHE_BUCKETS]; 104 struct modcache *item = xcalloc(1, sizeof(struct modcache)); 105 identifier_dup(&item->ident, ident); 106 item->scope = scope; 107 item->next = *bucket; 108 *bucket = item; 109 return scope; 110 }