16 static char *wrap_name_func(const char *name, char *(*fn)(char *))
18 char *copy = strdup(name);
19 char *result = fn(copy);
20 char *result_copy = strdup(result);
26 static char *basename_wrapper(const char *name)
28 return wrap_name_func(name, &basename);
31 static char *dirname_wrapper(const char *name)
33 return wrap_name_func(name, &dirname);
36 static bool file_exists(const char *filename)
38 FILE *f = fopen(filename, "r");
58 char *path; // path without file extension
59 char *filename; // path with file extension
60 char *environment; // directory path
62 UwUVMModuleType type; // native (.so) or plain (.uwu)
64 FunctionLink *functions; // required functions
65 size_t num_functions; // number of required functions
66 size_t loaded_functions; // number of loaded functions (<= num_functions)
70 AbstractSyntaxTree ast; // abstract syntax tree generated by parser (for plain modules)
71 void *lib; // dlopen() shared object handle (for native modules)
77 Module **modules; // loaded modules
78 size_t num_modules; // count for modules
80 char *std_path; // path to standard library
82 UwUVMProgram program; // the result program
87 // returns mallocated string
88 static inline char *get_filename(const char *module_path)
90 const char *try_names[3] = {
98 for (int i = 0; i < 3; i++) {
99 filename = asprintf_wrapper(try_names[i], module_path);
101 if (file_exists(filename))
110 // module_path is a mallocated string
111 static Module *require_module(CollectorState *state, char *module_path)
113 for (size_t i = 0; i < state->num_modules; i++) {
114 Module *module = state->modules[i];
116 if (strcmp(module_path, module->path) == 0) {
122 char *filename = get_filename(module_path);
125 error("error: module %s not found\n", module_path);
127 size_t filename_len = strlen(filename);
128 UwUVMModuleType type = (filename_len >= 3 && strcmp(filename + filename_len - 3, ".so") == 0) ? MODULE_NATIVE : MODULE_PLAIN;
130 state->modules = realloc(state->modules, sizeof *state->modules * ++state->num_modules);
131 Module *module = state->modules[state->num_modules - 1] = malloc(sizeof *module);
135 .filename = filename,
136 .environment = dirname_wrapper(module_path),
142 .loaded_functions = 0,
145 if (type == MODULE_PLAIN) {
146 module->handle.ast = parse_file(filename);
148 state->program.libraries = realloc(state->program.libraries, sizeof(void *) * ++state->program.num_libraries);
149 state->program.libraries[state->program.num_libraries - 1] = module->handle.lib = dlopen(filename, RTLD_LAZY);
151 char *err = dlerror();
159 static UwUVMFunction *require_function(CollectorState *state, Module *module, const char *name)
161 for (size_t i = 0; i < module->num_functions; i++) {
162 FunctionLink *link = &module->functions[i];
164 if (strcmp(link->name, name) == 0)
168 UwUVMFunction *ref = malloc(sizeof *ref);
169 ref->type = module->type;
171 state->program.functions = realloc(state->program.functions, sizeof *state->program.functions * ++state->program.num_functions);
172 state->program.functions[state->program.num_functions - 1] = ref;
174 module->functions = realloc(module->functions, sizeof *module->functions * ++module->num_functions);
175 module->functions[module->num_functions - 1] = (FunctionLink) {
176 .name = strdup(name),
183 static UwUVMFunction *resolve_function(CollectorState *state, Module *caller_module, const char *full_name)
185 size_t len = strlen(full_name);
188 for (fnname = &full_name[len - 1]; *fnname != ':' && fnname > full_name; fnname--)
195 error("error: empty function name\n");
197 Module *callee_module;
199 if (fnname == full_name) {
200 callee_module = caller_module;
202 const char *caller_path = caller_module->environment;
203 const char *callee_name = full_name;
205 if (*callee_name == ':') {
206 caller_path = state->std_path;
210 size_t path_len = fnname - callee_name;
211 char callee_path[path_len];
213 for (size_t i = 0; i < path_len; i++)
214 callee_path[i] = (i == path_len - 1) ? '\0'
215 : (callee_name[i] == ':') ? '/'
218 callee_module = require_module(state, asprintf_wrapper("%s/%s", caller_path, callee_path));
221 return require_function(state, callee_module, fnname);
224 static void translate_expression(CollectorState *state, Module *module, UwUVMExpression *vm_expr, ParseExpression *parse_expr)
226 UwUVMFunction *vm_function;
228 if (parse_expr->type == EX_FNNAME || parse_expr->type == EX_FNCALL) {
229 vm_function = resolve_function(state, module, parse_expr->value.str_value);
230 free(parse_expr->value.str_value);
233 switch (vm_expr->type = parse_expr->type) {
236 vm_expr->value.int_value = parse_expr->value.int_value;
240 vm_expr->value.str_value = parse_expr->value.str_value;
244 vm_expr->value.ref_value = vm_function;
248 vm_expr->value.cll_value.function = vm_function;
249 vm_expr->value.cll_value.args = malloc(sizeof(UwUVMExpression) * parse_expr->num_children);
250 vm_expr->value.cll_value.num_args = parse_expr->num_children;
252 for (size_t i = 0; i < parse_expr->num_children; i++)
253 translate_expression(state, module, &vm_expr->value.cll_value.args[i], parse_expr->children[i]);
255 if (parse_expr->children)
256 free(parse_expr->children);
266 static void load_functions(CollectorState *state, Module *module)
268 for (; module->loaded_functions < module->num_functions; module->loaded_functions++) {
269 FunctionLink *linkptr = &module->functions[module->loaded_functions];
270 FunctionLink link = *linkptr;
274 if (module->type == MODULE_PLAIN) {
275 ParseFunction **function = NULL;
277 for (size_t i = 0; i < module->handle.ast.num_functions; i++) {
278 ParseFunction **fn = &module->handle.ast.functions[i];
280 if (*fn && strcmp((*fn)->name, link.name) == 0) {
290 translate_expression(state, module, link.ref->value.plain = malloc(sizeof(UwUVMExpression)), (*function)->expression);
291 free((*function)->name);
297 char *symbol = asprintf_wrapper("uwu_%s", link.name);
298 linkptr->ref->value.native = dlsym(module->handle.lib, symbol);
307 error("error: no function %s in module %s\n", link.name, module->filename);
311 static void free_expression(ParseExpression *expr)
313 if (expr->type == EX_FNCALL) {
314 for (size_t i = 0; i < expr->num_children; i++)
315 free_expression(expr->children[i]);
318 free(expr->children);
321 if (expr->type != EX_INTLIT && expr->type != EX_ARGNUM)
322 free(expr->value.str_value);
327 UwUVMProgram create_program(const char *progname, const char *modname)
329 char *prog_dirname = dirname_wrapper(progname);
330 char *api_path = asprintf_wrapper("%s/api/api.so", prog_dirname);
332 CollectorState state = {
335 .std_path = asprintf_wrapper("%s/std", prog_dirname),
337 .api_library = dlopen(api_path, RTLD_NOW | RTLD_GLOBAL),
338 .main_function = NULL,
349 state.program.main_function = require_function(&state, require_module(&state, strdup(modname)), "main");
352 bool fully_loaded = true;
354 for (size_t i = 0; i < state.num_modules; i++) {
355 Module *module = state.modules[i];
358 printf("%s %lu/%lu\n", module->filename, module->loaded_functions, module->num_functions);
361 if (module->loaded_functions < module->num_functions) {
362 fully_loaded = false;
363 load_functions(&state, module);
371 free(state.std_path);
373 for (size_t i = 0; i < state.num_modules; i++) {
374 Module *module = state.modules[i];
377 free(module->filename);
378 free(module->environment);
380 for (size_t f = 0; f < module->num_functions; f++)
381 free(module->functions[f].name);
383 free(module->functions);
385 if (module->type == MODULE_PLAIN) {
386 for (size_t f = 0; f < module->handle.ast.num_functions; f++) {
387 ParseFunction *function = module->handle.ast.functions[f];
390 free_expression(function->expression);
391 free(function->name);
396 if (module->handle.ast.functions)
397 free(module->handle.ast.functions);
405 return state.program;