6 #include "common/err.h"
7 #include "common/str.h"
8 #include "common/file.h"
10 #include "common/dir.h"
24 char *path; // path without file extension
25 char *filename; // path with file extension
26 char *environment; // directory path
28 UwUVMModuleType type; // native (.so) or plain (.uwu)
30 FunctionLink *functions; // required functions
31 size_t num_functions; // number of required functions
32 size_t loaded_functions; // number of loaded functions (<= num_functions)
36 AbstractSyntaxTree ast; // abstract syntax tree generated by parser (for plain modules)
37 void *lib; // dlopen() shared object handle (for native modules)
43 Module **modules; // loaded modules
44 size_t num_modules; // count for modules
46 char **module_paths; // module search paths
47 size_t num_module_paths; // count for module_paths
48 char *module_paths_str; // module search paths, stringified
50 char *std_path; // path to standard library
52 Program program; // the result program
57 // returns mallocated string
58 static inline char *get_filename(const char *module_path)
60 const char *try_names[3] = {
68 for (int i = 0; i < 3; i++) {
69 filename = asprintf_wrapper(try_names[i], module_path);
71 if (file_exists(filename))
80 // module_path is a mallocated string
81 static Module *load_module(LoadState *state, char *module_path)
83 for (size_t i = 0; i < state->num_modules; i++) {
84 Module *module = state->modules[i];
86 if (strcmp(module_path, module->path) == 0) {
92 char *filename = get_filename(module_path);
99 size_t filename_len = strlen(filename);
100 UwUVMModuleType type = (filename_len >= 3 && strcmp(filename + filename_len - 3, ".so") == 0) ? MODULE_NATIVE : MODULE_PLAIN;
102 state->modules = realloc(state->modules, sizeof *state->modules * ++state->num_modules);
103 Module *module = state->modules[state->num_modules - 1] = malloc(sizeof *module);
107 .filename = filename,
108 .environment = dirname_wrapper(module_path),
114 .loaded_functions = 0,
117 if (type == MODULE_PLAIN) {
118 module->handle.ast = parse_file(filename);
120 state->program.libraries = realloc(state->program.libraries, sizeof(void *) * ++state->program.num_libraries);
121 state->program.libraries[state->program.num_libraries - 1] = module->handle.lib = dlopen(filename, RTLD_LAZY);
129 static UwUVMFunction *require_function(LoadState *state, Module *module, const char *name)
131 for (size_t i = 0; i < module->num_functions; i++) {
132 FunctionLink *link = &module->functions[i];
134 if (strcmp(link->name, name) == 0)
138 UwUVMFunction *ref = malloc(sizeof *ref);
139 ref->type = module->type;
141 state->program.functions = realloc(state->program.functions, sizeof *state->program.functions * ++state->program.num_functions);
142 state->program.functions[state->program.num_functions - 1] = ref;
144 module->functions = realloc(module->functions, sizeof *module->functions * ++module->num_functions);
145 module->functions[module->num_functions - 1] = (FunctionLink) {
146 .name = strdup(name),
153 static UwUVMFunction *resolve_function(LoadState *state, Module *caller_module, const char *full_name)
155 size_t len = strlen(full_name);
158 for (fnname = &full_name[len - 1]; *fnname != '.' && fnname > full_name; fnname--)
165 error("module error: empty function name referenced/called by module %s\n", caller_module->filename);
167 Module *callee_module;
169 if (fnname == full_name) {
170 callee_module = caller_module;
172 char **environments = state->module_paths;
173 size_t num_environments = state->num_module_paths;
174 char *environments_str = state->module_paths_str;
176 const char *callee_name = full_name;
178 if (*callee_name == '.') {
181 environments = &caller_module->environment;
182 num_environments = 1;
183 environments_str = caller_module->environment;
186 size_t path_len = fnname - callee_name;
187 char callee_path[path_len];
189 for (size_t i = 0; i < path_len; i++)
190 callee_path[i] = (i == path_len - 1) ? '\0'
191 : (callee_name[i] == '.') ? '/'
194 for (size_t i = 0; i < num_environments; i++)
195 if ((callee_module = load_module(state, asprintf_wrapper("%s/%s", environments[i], callee_path))))
199 error("module error: no module %s in path %s\n", callee_path, environments_str);
202 return require_function(state, callee_module, fnname);
205 static void translate_expression(LoadState *state, Module *module, UwUVMExpression *vm_expr, ParseExpression *parse_expr)
207 UwUVMFunction *vm_function;
209 if (parse_expr->type == EX_FNNAME || parse_expr->type == EX_FNCALL) {
210 vm_function = resolve_function(state, module, parse_expr->value.str_value);
211 free(parse_expr->value.str_value);
214 switch (vm_expr->type = parse_expr->type) {
217 vm_expr->value.int_value = parse_expr->value.int_value;
221 vm_expr->value.str_value = parse_expr->value.str_value;
225 vm_expr->value.ref_value = vm_function;
229 vm_expr->value.cll_value.function = vm_function;
230 vm_expr->value.cll_value.args = malloc(sizeof(UwUVMExpression) * parse_expr->num_children);
231 vm_expr->value.cll_value.num_args = parse_expr->num_children;
233 for (size_t i = 0; i < parse_expr->num_children; i++)
234 translate_expression(state, module, &vm_expr->value.cll_value.args[i], parse_expr->children[i]);
236 if (parse_expr->children)
237 free(parse_expr->children);
247 static void load_functions(LoadState *state, Module *module)
249 for (; module->loaded_functions < module->num_functions; module->loaded_functions++) {
250 FunctionLink *link = &module->functions[module->loaded_functions];
252 if (module->type == MODULE_PLAIN) {
253 ParseFunction **function = NULL;
255 for (size_t i = 0; i < module->handle.ast.num_functions; i++) {
256 ParseFunction **fn = &module->handle.ast.functions[i];
258 if (*fn && strcmp((*fn)->name, link->name) == 0) {
265 translate_expression(state, module, link->ref->value.plain = malloc(sizeof(UwUVMExpression)), (*function)->expression);
266 free((*function)->name);
271 error("module error: no function %s in module %s\n", link->name, module->filename);
274 char *symbol = asprintf_wrapper("uwu_%s", link->name);
275 link->ref->value.native = dlsym(module->handle.lib, symbol);
283 static void free_expression(ParseExpression *expr)
285 if (expr->type == EX_FNCALL) {
286 for (size_t i = 0; i < expr->num_children; i++)
287 free_expression(expr->children[i]);
290 free(expr->children);
293 if (expr->type != EX_INTLIT && expr->type != EX_ARGNUM)
294 free(expr->value.str_value);
299 Program load_program(const char *progname, const char *modname)
301 char *prog_dirname = dirname_wrapper(progname);
302 char *api_path = asprintf_wrapper("%s/api/api.so", prog_dirname);
308 .api_library = dlopen(api_path, RTLD_NOW | RTLD_GLOBAL),
309 .main_function = NULL,
317 char *uwu_module_path = getenv("UWU_MODULE_PATH");
319 if (uwu_module_path) {
320 char *uwu_module_path_ptr = state.module_paths_str = uwu_module_path;
321 char *uwu_module_path_base_ptr = uwu_module_path_ptr;
322 size_t uwu_module_path_len = 1;
324 state.num_module_paths = 0;
325 state.module_paths = NULL;
327 for (;; uwu_module_path_ptr++, uwu_module_path_len++) {
328 if (*uwu_module_path_ptr == '\0' || *uwu_module_path_ptr == ':') {
329 state.module_paths = realloc(state.module_paths, sizeof(char **) * ++state.num_module_paths);
330 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';
332 uwu_module_path_len = 0;
333 uwu_module_path_base_ptr = uwu_module_path_ptr + 1;
336 if (*uwu_module_path_ptr == '\0')
340 state.module_paths_str = asprintf_wrapper("%s/std", prog_dirname);
341 state.num_module_paths = 1;
342 state.module_paths = malloc(sizeof(char **));
343 state.module_paths[0] = state.module_paths_str;
349 Module *main_module = load_module(&state, strdup(modname));
352 error("module error: requested module %s not found\n", modname);
354 state.program.main_function = require_function(&state, main_module, "main");
357 bool fully_loaded = true;
359 for (size_t i = 0; i < state.num_modules; i++) {
360 Module *module = state.modules[i];
363 printf("%s %lu/%lu\n", module->filename, module->loaded_functions, module->num_functions);
366 if (module->loaded_functions < module->num_functions) {
367 fully_loaded = false;
368 load_functions(&state, module);
376 for (size_t i = 0; i < state.num_module_paths; i++)
377 free(state.module_paths[i]);
379 free(state.module_paths);
381 for (size_t i = 0; i < state.num_modules; i++) {
382 Module *module = state.modules[i];
385 free(module->filename);
386 free(module->environment);
388 for (size_t f = 0; f < module->num_functions; f++)
389 free(module->functions[f].name);
391 free(module->functions);
393 if (module->type == MODULE_PLAIN) {
394 for (size_t f = 0; f < module->handle.ast.num_functions; f++) {
395 ParseFunction *function = module->handle.ast.functions[f];
398 free_expression(function->expression);
399 free(function->name);
404 if (module->handle.ast.functions)
405 free(module->handle.ast.functions);
413 return state.program;