typedef struct
{
- char *path; // path without file extension
- char *filename; // path with file extension
- char *environment; // directory path
+ char *path; // path without file extension
+ char *filename; // path with file extension
+ char *environment; // directory path
- UwUVMModuleType type; // native (.so) or plain (.uwu)
+ UwUVMModuleType type; // native (.so) or plain (.uwu)
- FunctionLink *functions; // required functions
- size_t num_functions; // number of required functions
- size_t loaded_functions; // number of loaded functions (<= num_functions)
+ FunctionLink *functions; // required functions
+ size_t num_functions; // number of required functions
+ size_t loaded_functions; // number of loaded functions (<= num_functions)
union
{
- AbstractSyntaxTree ast; // abstract syntax tree generated by parser (for plain modules)
- void *lib; // dlopen() shared object handle (for native modules)
+ AbstractSyntaxTree ast; // abstract syntax tree generated by parser (for plain modules)
+ void *lib; // dlopen() shared object handle (for native modules)
} handle;
} Module;
typedef struct
{
- Module **modules; // loaded modules
- size_t num_modules; // count for modules
+ Module **modules; // loaded modules
+ size_t num_modules; // count for modules
- char *std_path; // path to standard library
+ char **module_paths; // module search paths
+ size_t num_module_paths; // count for module_paths
+ char *module_paths_str; // module search paths, stringified
- Program program; // the result program
+ char *std_path; // path to standard library
+
+ Program program; // the result program
} LoadState;
// functions
}
// module_path is a mallocated string
-static Module *require_module(LoadState *state, char *module_path)
+static Module *load_module(LoadState *state, char *module_path)
{
for (size_t i = 0; i < state->num_modules; i++) {
Module *module = state->modules[i];
char *filename = get_filename(module_path);
- if (! filename)
- error("module error: module %s not found\n", module_path);
+ if (! filename) {
+ free(module_path);
+ return NULL;
+ }
size_t filename_len = strlen(filename);
UwUVMModuleType type = (filename_len >= 3 && strcmp(filename + filename_len - 3, ".so") == 0) ? MODULE_NATIVE : MODULE_PLAIN;
size_t len = strlen(full_name);
const char *fnname;
- for (fnname = &full_name[len - 1]; *fnname != ':' && fnname > full_name; fnname--)
+ for (fnname = &full_name[len - 1]; *fnname != '.' && fnname > full_name; fnname--)
;
- if (*fnname == ':')
+ if (*fnname == '.')
fnname++;
if (*fnname == '\0')
if (fnname == full_name) {
callee_module = caller_module;
} else {
- const char *caller_path = caller_module->environment;
+ char **environments = state->module_paths;
+ size_t num_environments = state->num_module_paths;
+ char *environments_str = state->module_paths_str;
+
const char *callee_name = full_name;
- if (*callee_name == ':') {
- caller_path = state->std_path;
+ if (*callee_name == '.') {
callee_name++;
+
+ environments = &caller_module->environment;
+ num_environments = 1;
+ environments_str = caller_module->environment;
}
size_t path_len = fnname - callee_name;
for (size_t i = 0; i < path_len; i++)
callee_path[i] = (i == path_len - 1) ? '\0'
- : (callee_name[i] == ':') ? '/'
+ : (callee_name[i] == '.') ? '/'
: callee_name[i];
- callee_module = require_module(state, asprintf_wrapper("%s/%s", caller_path, callee_path));
+ for (size_t i = 0; i < num_environments; i++)
+ if ((callee_module = load_module(state, asprintf_wrapper("%s/%s", environments[i], callee_path))))
+ break;
+
+ if (! callee_module)
+ error("module error: no module %s in path %s\n", callee_path, environments_str);
}
return require_function(state, callee_module, fnname);
LoadState state = {
.modules = NULL,
.num_modules = 0,
- .std_path = asprintf_wrapper("%s/std", prog_dirname),
.program = {
.api_library = dlopen(api_path, RTLD_NOW | RTLD_GLOBAL),
.main_function = NULL,
},
};
+ char *uwu_module_path = getenv("UWU_MODULE_PATH");
+
+ if (uwu_module_path) {
+ char *uwu_module_path_ptr = state.module_paths_str = uwu_module_path;
+ char *uwu_module_path_base_ptr = uwu_module_path_ptr;
+ size_t uwu_module_path_len = 1;
+
+ state.num_module_paths = 0;
+ state.module_paths = NULL;
+
+ for (;; uwu_module_path_ptr++, uwu_module_path_len++) {
+ if (*uwu_module_path_ptr == '\0' || *uwu_module_path_ptr == ':') {
+ state.module_paths = realloc(state.module_paths, sizeof(char **) * ++state.num_module_paths);
+ 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';
+
+ uwu_module_path_len = 0;
+ uwu_module_path_base_ptr = uwu_module_path_ptr + 1;
+ }
+
+ if (*uwu_module_path_ptr == '\0')
+ break;
+ }
+ } else {
+ state.module_paths_str = asprintf_wrapper("%s/std", prog_dirname);
+ state.num_module_paths = 1;
+ state.module_paths = malloc(sizeof(char **));
+ state.module_paths[0] = state.module_paths_str;
+ }
+
free(prog_dirname);
free(api_path);
- state.program.main_function = require_function(&state, require_module(&state, strdup(modname)), "main");
+ Module *main_module = load_module(&state, strdup(modname));
+
+ if (! main_module)
+ error("module error: requested module %s not found\n", modname);
+
+ state.program.main_function = require_function(&state, main_module, "main");
while (true) {
bool fully_loaded = true;
break;
}
- free(state.std_path);
+ for (size_t i = 0; i < state.num_module_paths; i++)
+ free(state.module_paths[i]);
+
+ free(state.module_paths);
for (size_t i = 0; i < state.num_modules; i++) {
Module *module = state.modules[i];