harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

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 }