7 #include "common/err.h"
8 #include "common/str.h"
9 #include "common/file.h"
10 #include "common/dl.h"
18 static char *dirname_wrapper(const char *name)
20 char *copy = strdup(name);
21 char *result = dirname(copy);
22 char *result_copy = strdup(result);
38 char *path; // path without file extension
39 char *filename; // path with file extension
40 char *environment; // directory path
42 UwUVMModuleType type; // native (.so) or plain (.uwu)
44 FunctionLink *functions; // required functions
45 size_t num_functions; // number of required functions
46 size_t loaded_functions; // number of loaded functions (<= num_functions)
50 AbstractSyntaxTree ast; // abstract syntax tree generated by parser (for plain modules)
51 void *lib; // dlopen() shared object handle (for native modules)
57 Module **modules; // loaded modules
58 size_t num_modules; // count for modules
60 char **module_paths; // module search paths
61 size_t num_module_paths; // count for module_paths
62 char *module_paths_str; // module search paths, stringified
64 char *std_path; // path to standard library
66 Program program; // the result program
71 // returns mallocated string
72 static inline char *get_filename(const char *module_path)
74 const char *try_names[3] = {
82 for (int i = 0; i < 3; i++) {
83 filename = asprintf_wrapper(try_names[i], module_path);
85 if (file_exists(filename))
94 // module_path is a mallocated string
95 static Module *load_module(LoadState *state, char *module_path)
97 for (size_t i = 0; i < state->num_modules; i++) {
98 Module *module = state->modules[i];
100 if (strcmp(module_path, module->path) == 0) {
106 char *filename = get_filename(module_path);
113 size_t filename_len = strlen(filename);
114 UwUVMModuleType type = (filename_len >= 3 && strcmp(filename + filename_len - 3, ".so") == 0) ? MODULE_NATIVE : MODULE_PLAIN;
116 state->modules = realloc(state->modules, sizeof *state->modules * ++state->num_modules);
117 Module *module = state->modules[state->num_modules - 1] = malloc(sizeof *module);
121 .filename = filename,
122 .environment = dirname_wrapper(module_path),
128 .loaded_functions = 0,
131 if (type == MODULE_PLAIN) {
132 module->handle.ast = parse_file(filename);
134 state->program.libraries = realloc(state->program.libraries, sizeof(void *) * ++state->program.num_libraries);
135 state->program.libraries[state->program.num_libraries - 1] = module->handle.lib = dlopen(filename, RTLD_LAZY);
143 static UwUVMFunction *require_function(LoadState *state, Module *module, const char *name)
145 for (size_t i = 0; i < module->num_functions; i++) {
146 FunctionLink *link = &module->functions[i];
148 if (strcmp(link->name, name) == 0)
152 UwUVMFunction *ref = malloc(sizeof *ref);
153 ref->type = module->type;
155 state->program.functions = realloc(state->program.functions, sizeof *state->program.functions * ++state->program.num_functions);
156 state->program.functions[state->program.num_functions - 1] = ref;
158 module->functions = realloc(module->functions, sizeof *module->functions * ++module->num_functions);
159 module->functions[module->num_functions - 1] = (FunctionLink) {
160 .name = strdup(name),
167 static UwUVMFunction *resolve_function(LoadState *state, Module *caller_module, const char *full_name)
169 size_t len = strlen(full_name);
172 for (fnname = &full_name[len - 1]; *fnname != '.' && fnname > full_name; fnname--)
179 error("module error: empty function name referenced/called by module %s\n", caller_module->filename);
181 Module *callee_module;
183 if (fnname == full_name) {
184 callee_module = caller_module;
186 char **environments = state->module_paths;
187 size_t num_environments = state->num_module_paths;
188 char *environments_str = state->module_paths_str;
190 const char *callee_name = full_name;
192 if (*callee_name == '.') {
195 environments = &caller_module->environment;
196 num_environments = 1;
197 environments_str = caller_module->environment;
200 size_t path_len = fnname - callee_name;
201 char callee_path[path_len];
203 for (size_t i = 0; i < path_len; i++)
204 callee_path[i] = (i == path_len - 1) ? '\0'
205 : (callee_name[i] == '.') ? '/'
208 for (size_t i = 0; i < num_environments; i++)
209 if ((callee_module = load_module(state, asprintf_wrapper("%s/%s", environments[i], callee_path))))
213 error("module error: no module %s in path %s\n", callee_path, environments_str);
216 return require_function(state, callee_module, fnname);
219 static void translate_expression(LoadState *state, Module *module, UwUVMExpression *vm_expr, ParseExpression *parse_expr)
221 UwUVMFunction *vm_function;
223 if (parse_expr->type == EX_FNNAME || parse_expr->type == EX_FNCALL) {
224 vm_function = resolve_function(state, module, parse_expr->value.str_value);
225 free(parse_expr->value.str_value);
228 switch (vm_expr->type = parse_expr->type) {
231 vm_expr->value.int_value = parse_expr->value.int_value;
235 vm_expr->value.str_value = parse_expr->value.str_value;
239 vm_expr->value.ref_value = vm_function;
243 vm_expr->value.cll_value.function = vm_function;
244 vm_expr->value.cll_value.args = malloc(sizeof(UwUVMExpression) * parse_expr->num_children);
245 vm_expr->value.cll_value.num_args = parse_expr->num_children;
247 for (size_t i = 0; i < parse_expr->num_children; i++)
248 translate_expression(state, module, &vm_expr->value.cll_value.args[i], parse_expr->children[i]);
250 if (parse_expr->children)
251 free(parse_expr->children);
261 static void load_functions(LoadState *state, Module *module)
263 for (; module->loaded_functions < module->num_functions; module->loaded_functions++) {
264 FunctionLink *link = &module->functions[module->loaded_functions];
266 if (module->type == MODULE_PLAIN) {
267 ParseFunction **function = NULL;
269 for (size_t i = 0; i < module->handle.ast.num_functions; i++) {
270 ParseFunction **fn = &module->handle.ast.functions[i];
272 if (*fn && strcmp((*fn)->name, link->name) == 0) {
279 translate_expression(state, module, link->ref->value.plain = malloc(sizeof(UwUVMExpression)), (*function)->expression);
280 free((*function)->name);
285 error("module error: no function %s in module %s\n", link->name, module->filename);
288 char *symbol = asprintf_wrapper("uwu_%s", link->name);
289 link->ref->value.native = dlsym(module->handle.lib, symbol);
297 static void free_expression(ParseExpression *expr)
299 if (expr->type == EX_FNCALL) {
300 for (size_t i = 0; i < expr->num_children; i++)
301 free_expression(expr->children[i]);
304 free(expr->children);
307 if (expr->type != EX_INTLIT && expr->type != EX_ARGNUM)
308 free(expr->value.str_value);
313 Program load_program(const char *progname, const char *modname)
315 char *prog_dirname = dirname_wrapper(progname);
316 char *api_path = asprintf_wrapper("%s/api/api.so", prog_dirname);
322 .api_library = dlopen(api_path, RTLD_NOW | RTLD_GLOBAL),
323 .main_function = NULL,
331 char *uwu_module_path = getenv("UWU_MODULE_PATH");
333 if (uwu_module_path) {
334 char *uwu_module_path_ptr = state.module_paths_str = uwu_module_path;
335 char *uwu_module_path_base_ptr = uwu_module_path_ptr;
336 size_t uwu_module_path_len = 1;
338 state.num_module_paths = 0;
339 state.module_paths = NULL;
341 for (;; uwu_module_path_ptr++, uwu_module_path_len++) {
342 if (*uwu_module_path_ptr == '\0' || *uwu_module_path_ptr == ':') {
343 state.module_paths = realloc(state.module_paths, sizeof(char **) * ++state.num_module_paths);
344 strncpy(state.module_paths[state.num_module_paths - 1] = malloc(uwu_module_path_len), uwu_module_path_base_ptr, uwu_module_path_len)[uwu_module_path_len - 1] = '\0';
346 uwu_module_path_len = 0;
347 uwu_module_path_base_ptr = uwu_module_path_ptr + 1;
350 if (*uwu_module_path_ptr == '\0')
354 state.module_paths_str = asprintf_wrapper("%s/std", prog_dirname);
355 state.num_module_paths = 1;
356 state.module_paths = malloc(sizeof(char **));
357 state.module_paths[0] = state.module_paths_str;
363 Module *main_module = load_module(&state, strdup(modname));
366 error("module error: requested module %s not found\n", modname);
368 state.program.main_function = require_function(&state, main_module, "main");
371 bool fully_loaded = true;
373 for (size_t i = 0; i < state.num_modules; i++) {
374 Module *module = state.modules[i];
377 printf("%s %lu/%lu\n", module->filename, module->loaded_functions, module->num_functions);
380 if (module->loaded_functions < module->num_functions) {
381 fully_loaded = false;
382 load_functions(&state, module);
390 for (size_t i = 0; i < state.num_module_paths; i++)
391 free(state.module_paths[i]);
393 free(state.module_paths);
395 for (size_t i = 0; i < state.num_modules; i++) {
396 Module *module = state.modules[i];
399 free(module->filename);
400 free(module->environment);
402 for (size_t f = 0; f < module->num_functions; f++)
403 free(module->functions[f].name);
405 free(module->functions);
407 if (module->type == MODULE_PLAIN) {
408 for (size_t f = 0; f < module->handle.ast.num_functions; f++) {
409 ParseFunction *function = module->handle.ast.functions[f];
412 free_expression(function->expression);
413 free(function->name);
418 if (module->handle.ast.functions)
419 free(module->handle.ast.functions);
427 return state.program;