]> git.lizzy.rs Git - uwu-lang.git/commitdiff
Allow passing arguments to program, refactor directory structure
authorElias Fleckenstein <eliasfleckenstein@web.de>
Thu, 30 Dec 2021 17:31:53 +0000 (18:31 +0100)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Thu, 30 Dec 2021 17:31:53 +0000 (18:31 +0100)
29 files changed:
Makefile
README.md
api/int.c
api/ref.c
api/util.c
api/vm.c
api/vm.h
common/err.h [new file with mode: 0644]
common/str.h [new file with mode: 0644]
example/print_args.uwu [new file with mode: 0644]
src/collect.c [deleted file]
src/collect.h [deleted file]
src/err.h [deleted file]
src/expression.h [deleted file]
src/load.c [new file with mode: 0644]
src/load.h [new file with mode: 0644]
src/main.c
src/parse.c
src/parse.h
src/run.c [new file with mode: 0644]
src/run.h [new file with mode: 0644]
src/util.h [deleted file]
src/vm.c [deleted file]
src/vm.h [deleted file]
std/bool.c
std/int.c
std/nil.c
std/ref.c
std/str.c

index 17c69223ea41687819cdc425f2ea389b1f4ea20f..da9c509b7cb9c6f0b63fb2086c69d9b285f5c967 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 all: uwu std api
 
 uwu: src/*.c src/*.h
-       gcc -g src/*.c -o uwu -ldl -D_GNU_SOURCE
+       gcc -g -I.               src/*.c   -o uwu        -D_GNU_SOURCE -ldl
 
 .PHONY: std api
 
@@ -9,10 +9,10 @@ std: std/bool.so std/int.so std/str.so std/nil.so std/ref.so
 api: api/api.so
 
 std/%.so: std/%.c
-       gcc -g -shared -fpic $< -o $@ -D_GNU_SOURCE
+       gcc -g -I. -shared -fpic $< -o $@ -D_GNU_SOURCE
 
 api/api.so: api/*.c api/*.h
-       gcc -g -shared -fpic api/*.c -o api/api.so -D_GNU_SOURCE
+       gcc -g -I. -shared -fpic api/*.c   -o api/api.so -D_GNU_SOURCE
 
 .PHONY: clean
 
index 211c407f9a604d8e5b89a8f67adddcaf5dcc8608..c762b4a520e66d63b522586fb87dc87758b289a2 100644 (file)
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ make
 To run:
 
 ```
-./uwu <module>
+./uwu <module> <args>
 ```
 
 `<module>` is a path relative to the current directory.
index 8446d1d7c1a2c01b2caeb6451b0a672a6f681778..b1e0c69a98305294661e756b43a7a6cf8be1527f 100644 (file)
--- a/api/int.c
+++ b/api/int.c
@@ -1,5 +1,5 @@
 #include <stdlib.h>
-#include "../src/util.h"
+#include "common/str.h"
 #include "int.h"
 
 UwUVMValue uwuint_create(int value)
index 43eb68e4cb0b95d3bb35f7e75211a35e22ea5b5c..517869ed1ecf7446898ad253add73a5494816730 100644 (file)
--- a/api/ref.c
+++ b/api/ref.c
@@ -1,4 +1,4 @@
-#include "../src/util.h"
+#include "common/str.h"
 #include "ref.h"
 
 UwUVMValue uwuref_create(UwUVMFunction *value)
index c3e8a38aeb1132a60cc1875f6bb8e0e268105443..e6f06502ffdcc0751713b37f5d0f14180eb36820 100644 (file)
@@ -1,4 +1,4 @@
-#include "../src/err.h"
+#include "common/err.h"
 #include "util.h"
 #include "bool.h"
 
index 5cab6c08465485025b5fc7cc89dd831ed2c643c9..8374050b3fbdd9874da14473df20ea48d16192aa 100644 (file)
--- a/api/vm.c
+++ b/api/vm.c
@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include "../src/err.h"
+#include "common/err.h"
 #include "vm.h"
 #include "str.h"
 #include "ref.h"
index 81465f83b7088792b3885e0887d6f45b7c597a9a..fc761d3e3f9815eef779082e682337cb4fad029b 100644 (file)
--- a/api/vm.h
+++ b/api/vm.h
@@ -3,7 +3,6 @@
 
 #include <stddef.h>
 #include <stdbool.h>
-#include "../src/expression.h"
 
 typedef enum
 {
@@ -11,6 +10,16 @@ typedef enum
        MODULE_NATIVE,
 } UwUVMModuleType;
 
+typedef enum
+{
+       EX_UNINIT,
+       EX_INTLIT,
+       EX_STRLIT,
+       EX_ARGNUM,
+       EX_FNNAME,
+       EX_FNCALL,
+} UwUVMExpressionType;
+
 typedef struct
 {
        void *(*clone)(void *data);
@@ -46,7 +55,7 @@ typedef struct
 
 typedef struct UwUVMExpression
 {
-       ExpressionType type;
+       UwUVMExpressionType type;
        union
        {
                struct
@@ -61,16 +70,6 @@ typedef struct UwUVMExpression
        } value;
 } UwUVMExpression;
 
-typedef struct
-{
-       void *api_library;
-       UwUVMFunction *main_function;
-       UwUVMFunction     **functions;
-       size_t          num_functions;
-       void     **libraries;
-       size_t num_libraries;
-} UwUVMProgram;
-
 UwUVMValue uwuvm_clone_value(UwUVMValue value);
 void       uwuvm_delet_value(UwUVMValue value);
 char      *uwuvm_print_value(UwUVMValue value);
diff --git a/common/err.h b/common/err.h
new file mode 100644 (file)
index 0000000..1dccbf9
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _ERR_H_
+#define _ERR_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+static inline void error(const char *format, ...)
+{
+       va_list args;
+       va_start(args, format);
+       vfprintf(stderr, format, args);
+       va_end(args);
+       exit(1);
+}
+
+#endif
diff --git a/common/str.h b/common/str.h
new file mode 100644 (file)
index 0000000..b0baa37
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <stdio.h>
+#include <stdarg.h>
+
+static inline char *asprintf_wrapper(const char *format, ...)
+{
+       va_list args;
+       va_start(args, format);
+       char *ptr;
+       vasprintf(&ptr, format, args);
+       va_end(args);
+       return ptr;
+}
+
+#endif
diff --git a/example/print_args.uwu b/example/print_args.uwu
new file mode 100644 (file)
index 0000000..2256a88
--- /dev/null
@@ -0,0 +1,5 @@
+main :str:cat(
+       $0,
+       $1,
+       $2
+)
diff --git a/src/collect.c b/src/collect.c
deleted file mode 100644 (file)
index ae15513..0000000
+++ /dev/null
@@ -1,406 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <libgen.h>
-#include <dlfcn.h>
-#include "err.h"
-#include "util.h"
-#include "collect.h"
-#include "parse.h"
-
-#define DEBUG 0
-
-// helper functions
-
-static char *wrap_name_func(const char *name, char *(*fn)(char *))
-{
-       char *copy = strdup(name);
-       char *result = fn(copy);
-       char *result_copy = strdup(result);
-
-       free(copy);
-       return result_copy;
-}
-
-static char *basename_wrapper(const char *name)
-{
-       return wrap_name_func(name, &basename);
-}
-
-static char *dirname_wrapper(const char *name)
-{
-       return wrap_name_func(name, &dirname);
-}
-
-static bool file_exists(const char *filename)
-{
-       FILE *f = fopen(filename, "r");
-
-       if (f) {
-               fclose(f);
-               return true;
-       }
-
-       return false;
-}
-
-// type definitions
-
-typedef struct
-{
-       char *name;
-       UwUVMFunction *ref;
-} FunctionLink;
-
-typedef struct
-{
-       char *path;                                     // path without file extension
-       char *filename;                         // path with file extension
-       char *environment;                      // directory path
-
-       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)
-
-       union
-       {
-               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
-
-       char *std_path;                         // path to standard library
-
-       UwUVMProgram program;                   // the result program
-} CollectorState;
-
-// functions
-
-// returns mallocated string
-static inline char *get_filename(const char *module_path)
-{
-       const char *try_names[3] = {
-               "%s",
-               "%s.uwu",
-               "%s.so",
-       };
-
-       char *filename;
-
-       for (int i = 0; i < 3; i++) {
-               filename = asprintf_wrapper(try_names[i], module_path);
-
-               if (file_exists(filename))
-                       return filename;
-               else
-                       free(filename);
-       }
-
-       return NULL;
-}
-
-// module_path is a mallocated string
-static Module *require_module(CollectorState *state, char *module_path)
-{
-       for (size_t i = 0; i < state->num_modules; i++) {
-               Module *module = state->modules[i];
-
-               if (strcmp(module_path, module->path) == 0) {
-                       free(module_path);
-                       return module;
-               }
-       }
-
-       char *filename = get_filename(module_path);
-
-       if (! filename)
-               error("error: module %s not found\n", module_path);
-
-       size_t filename_len = strlen(filename);
-       UwUVMModuleType type = (filename_len >= 3 && strcmp(filename + filename_len - 3, ".so") == 0) ? MODULE_NATIVE : MODULE_PLAIN;
-
-       state->modules = realloc(state->modules, sizeof *state->modules * ++state->num_modules);
-       Module *module = state->modules[state->num_modules - 1] = malloc(sizeof *module);
-
-       *module = (Module) {
-               .path = module_path,
-               .filename = filename,
-               .environment = dirname_wrapper(module_path),
-
-               .type = type,
-
-               .functions = NULL,
-               .num_functions = 0,
-               .loaded_functions = 0,
-       };
-
-       if (type == MODULE_PLAIN) {
-               module->handle.ast = parse_file(filename);
-       } else {
-               state->program.libraries = realloc(state->program.libraries, sizeof(void *) * ++state->program.num_libraries);
-               state->program.libraries[state->program.num_libraries - 1] = module->handle.lib = dlopen(filename, RTLD_LAZY);
-
-               char *err = dlerror();
-               if (err)
-                       error("%s\n", err);
-       }
-
-       return module;
-}
-
-static UwUVMFunction *require_function(CollectorState *state, Module *module, const char *name)
-{
-       for (size_t i = 0; i < module->num_functions; i++) {
-               FunctionLink *link = &module->functions[i];
-
-               if (strcmp(link->name, name) == 0)
-                       return link->ref;
-       }
-
-       UwUVMFunction *ref = malloc(sizeof *ref);
-       ref->type = module->type;
-
-       state->program.functions = realloc(state->program.functions, sizeof *state->program.functions * ++state->program.num_functions);
-       state->program.functions[state->program.num_functions - 1] = ref;
-
-       module->functions = realloc(module->functions, sizeof *module->functions * ++module->num_functions);
-       module->functions[module->num_functions - 1] = (FunctionLink) {
-               .name = strdup(name),
-               .ref = ref,
-       };
-
-       return ref;
-}
-
-static UwUVMFunction *resolve_function(CollectorState *state, Module *caller_module, const char *full_name)
-{
-       size_t len = strlen(full_name);
-
-       const char *fnname;
-       for (fnname = &full_name[len - 1]; *fnname != ':' && fnname > full_name; fnname--)
-               ;
-
-       if (*fnname == ':')
-               fnname++;
-
-       if (*fnname == '\0')
-               error("error: empty function name\n");
-
-       Module *callee_module;
-
-       if (fnname == full_name) {
-               callee_module = caller_module;
-       } else {
-               const char *caller_path = caller_module->environment;
-               const char *callee_name = full_name;
-
-               if (*callee_name == ':') {
-                       caller_path = state->std_path;
-                       callee_name++;
-               }
-
-               size_t path_len = fnname - callee_name;
-               char callee_path[path_len];
-
-               for (size_t i = 0; i < path_len; i++)
-                       callee_path[i] = (i == path_len - 1) ? '\0'
-                               : (callee_name[i] == ':') ? '/'
-                               : callee_name[i];
-
-               callee_module = require_module(state, asprintf_wrapper("%s/%s", caller_path, callee_path));
-       }
-
-       return require_function(state, callee_module, fnname);
-}
-
-static void translate_expression(CollectorState *state, Module *module, UwUVMExpression *vm_expr, ParseExpression *parse_expr)
-{
-       UwUVMFunction *vm_function;
-
-       if (parse_expr->type == EX_FNNAME || parse_expr->type == EX_FNCALL) {
-               vm_function = resolve_function(state, module, parse_expr->value.str_value);
-               free(parse_expr->value.str_value);
-       }
-
-       switch (vm_expr->type = parse_expr->type) {
-               case EX_INTLIT:
-               case EX_ARGNUM:
-                       vm_expr->value.int_value = parse_expr->value.int_value;
-                       break;
-
-               case EX_STRLIT:
-                       vm_expr->value.str_value = parse_expr->value.str_value;
-                       break;
-
-               case EX_FNNAME:
-                       vm_expr->value.ref_value = vm_function;
-                       break;
-
-               case EX_FNCALL:
-                       vm_expr->value.cll_value.function = vm_function;
-                       vm_expr->value.cll_value.args = malloc(sizeof(UwUVMExpression) * parse_expr->num_children);
-                       vm_expr->value.cll_value.num_args = parse_expr->num_children;
-
-                       for (size_t i = 0; i < parse_expr->num_children; i++)
-                               translate_expression(state, module, &vm_expr->value.cll_value.args[i], parse_expr->children[i]);
-
-                       if (parse_expr->children)
-                               free(parse_expr->children);
-                       break;
-
-               default:
-                       break;
-       }
-
-       free(parse_expr);
-}
-
-static void load_functions(CollectorState *state, Module *module)
-{
-       for (; module->loaded_functions < module->num_functions; module->loaded_functions++) {
-               FunctionLink *linkptr = &module->functions[module->loaded_functions];
-               FunctionLink link = *linkptr;
-
-               bool found = false;
-
-               if (module->type == MODULE_PLAIN) {
-                       ParseFunction **function = NULL;
-
-                       for (size_t i = 0; i < module->handle.ast.num_functions; i++) {
-                               ParseFunction **fn = &module->handle.ast.functions[i];
-
-                               if (*fn && strcmp((*fn)->name, link.name) == 0) {
-                                       function = fn;
-                                       break;
-                               }
-                       }
-
-                       if (function) {
-                               found = true;
-                               linkptr = NULL;
-
-                               translate_expression(state, module, link.ref->value.plain = malloc(sizeof(UwUVMExpression)), (*function)->expression);
-                               free((*function)->name);
-                               free(*function);
-
-                               *function = NULL;
-                       }
-               } else {
-                       char *symbol = asprintf_wrapper("uwu_%s", link.name);
-                       linkptr->ref->value.native = dlsym(module->handle.lib, symbol);
-
-                       if (! dlerror())
-                               found = true;
-
-                       free(symbol);
-               }
-
-               if (! found)
-                       error("error: no function %s in module %s\n", link.name, module->filename);
-       }
-}
-
-static void free_expression(ParseExpression *expr)
-{
-       if (expr->type == EX_FNCALL) {
-               for (size_t i = 0; i < expr->num_children; i++)
-                       free_expression(expr->children[i]);
-
-               if (expr->children)
-                       free(expr->children);
-       }
-
-       if (expr->type != EX_INTLIT && expr->type != EX_ARGNUM)
-               free(expr->value.str_value);
-
-       free(expr);
-}
-
-UwUVMProgram create_program(const char *progname, const char *modname)
-{
-       char *prog_dirname = dirname_wrapper(progname);
-       char *api_path = asprintf_wrapper("%s/api/api.so", prog_dirname);
-
-       CollectorState 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,
-                       .functions = NULL,
-                       .num_functions = 0,
-                       .libraries = NULL,
-                       .num_libraries = 0,
-               },
-       };
-
-       free(prog_dirname);
-       free(api_path);
-
-       state.program.main_function = require_function(&state, require_module(&state, strdup(modname)), "main");
-
-       while (true) {
-               bool fully_loaded = true;
-
-               for (size_t i = 0; i < state.num_modules; i++) {
-                       Module *module = state.modules[i];
-
-#if DEBUG
-                       printf("%s %lu/%lu\n", module->filename, module->loaded_functions, module->num_functions);
-#endif
-
-                       if (module->loaded_functions < module->num_functions) {
-                               fully_loaded = false;
-                               load_functions(&state, module);
-                       }
-               }
-
-               if (fully_loaded)
-                       break;
-       }
-
-       free(state.std_path);
-
-       for (size_t i = 0; i < state.num_modules; i++) {
-               Module *module = state.modules[i];
-
-               free(module->path);
-               free(module->filename);
-               free(module->environment);
-
-               for (size_t f = 0; f < module->num_functions; f++)
-                       free(module->functions[f].name);
-
-               free(module->functions);
-
-               if (module->type == MODULE_PLAIN) {
-                       for (size_t f = 0; f < module->handle.ast.num_functions; f++) {
-                               ParseFunction *function = module->handle.ast.functions[f];
-
-                               if (function) {
-                                       free_expression(function->expression);
-                                       free(function->name);
-                                       free(function);
-                               }
-                       }
-
-                       if (module->handle.ast.functions)
-                               free(module->handle.ast.functions);
-               }
-
-               free(module);
-       }
-
-       free(state.modules);
-
-       return state.program;
-}
diff --git a/src/collect.h b/src/collect.h
deleted file mode 100644 (file)
index da118a5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _COLLECT_H_
-#define _COLLECT_H_
-
-#include "../api/vm.h"
-
-UwUVMProgram create_program(const char *progname, const char *modname);
-
-#endif
diff --git a/src/err.h b/src/err.h
deleted file mode 100644 (file)
index 1dccbf9..0000000
--- a/src/err.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _ERR_H_
-#define _ERR_H_
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-static inline void error(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       vfprintf(stderr, format, args);
-       va_end(args);
-       exit(1);
-}
-
-#endif
diff --git a/src/expression.h b/src/expression.h
deleted file mode 100644 (file)
index 55d10f7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _EXPRESSION_H_
-#define _EXPRESSION_H_
-
-typedef enum
-{
-       EX_UNINIT,
-       EX_INTLIT,
-       EX_STRLIT,
-       EX_ARGNUM,
-       EX_FNNAME,
-       EX_FNCALL,
-} ExpressionType;
-
-#endif
diff --git a/src/load.c b/src/load.c
new file mode 100644 (file)
index 0000000..edeba97
--- /dev/null
@@ -0,0 +1,400 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <dlfcn.h>
+#include "common/err.h"
+#include "common/str.h"
+#include "load.h"
+#include "parse.h"
+
+#define DEBUG 0
+
+// helper functions
+
+static char *wrap_name_func(const char *name, char *(*fn)(char *))
+{
+       char *copy = strdup(name);
+       char *result = fn(copy);
+       char *result_copy = strdup(result);
+
+       free(copy);
+       return result_copy;
+}
+
+static char *basename_wrapper(const char *name)
+{
+       return wrap_name_func(name, &basename);
+}
+
+static char *dirname_wrapper(const char *name)
+{
+       return wrap_name_func(name, &dirname);
+}
+
+static bool file_exists(const char *filename)
+{
+       FILE *f = fopen(filename, "r");
+
+       if (f) {
+               fclose(f);
+               return true;
+       }
+
+       return false;
+}
+
+// type definitions
+
+typedef struct
+{
+       char *name;
+       UwUVMFunction *ref;
+} FunctionLink;
+
+typedef struct
+{
+       char *path;                                     // path without file extension
+       char *filename;                         // path with file extension
+       char *environment;                      // directory path
+
+       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)
+
+       union
+       {
+               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
+
+       char *std_path;                         // path to standard library
+
+       Program program;                        // the result program
+} LoadState;
+
+// functions
+
+// returns mallocated string
+static inline char *get_filename(const char *module_path)
+{
+       const char *try_names[3] = {
+               "%s",
+               "%s.uwu",
+               "%s.so",
+       };
+
+       char *filename;
+
+       for (int i = 0; i < 3; i++) {
+               filename = asprintf_wrapper(try_names[i], module_path);
+
+               if (file_exists(filename))
+                       return filename;
+               else
+                       free(filename);
+       }
+
+       return NULL;
+}
+
+// module_path is a mallocated string
+static Module *require_module(LoadState *state, char *module_path)
+{
+       for (size_t i = 0; i < state->num_modules; i++) {
+               Module *module = state->modules[i];
+
+               if (strcmp(module_path, module->path) == 0) {
+                       free(module_path);
+                       return module;
+               }
+       }
+
+       char *filename = get_filename(module_path);
+
+       if (! filename)
+               error("error: module %s not found\n", module_path);
+
+       size_t filename_len = strlen(filename);
+       UwUVMModuleType type = (filename_len >= 3 && strcmp(filename + filename_len - 3, ".so") == 0) ? MODULE_NATIVE : MODULE_PLAIN;
+
+       state->modules = realloc(state->modules, sizeof *state->modules * ++state->num_modules);
+       Module *module = state->modules[state->num_modules - 1] = malloc(sizeof *module);
+
+       *module = (Module) {
+               .path = module_path,
+               .filename = filename,
+               .environment = dirname_wrapper(module_path),
+
+               .type = type,
+
+               .functions = NULL,
+               .num_functions = 0,
+               .loaded_functions = 0,
+       };
+
+       if (type == MODULE_PLAIN) {
+               module->handle.ast = parse_file(filename);
+       } else {
+               state->program.libraries = realloc(state->program.libraries, sizeof(void *) * ++state->program.num_libraries);
+               state->program.libraries[state->program.num_libraries - 1] = module->handle.lib = dlopen(filename, RTLD_LAZY);
+
+               char *err = dlerror();
+               if (err)
+                       error("library error: %s\n", err);
+       }
+
+       return module;
+}
+
+static UwUVMFunction *require_function(LoadState *state, Module *module, const char *name)
+{
+       for (size_t i = 0; i < module->num_functions; i++) {
+               FunctionLink *link = &module->functions[i];
+
+               if (strcmp(link->name, name) == 0)
+                       return link->ref;
+       }
+
+       UwUVMFunction *ref = malloc(sizeof *ref);
+       ref->type = module->type;
+
+       state->program.functions = realloc(state->program.functions, sizeof *state->program.functions * ++state->program.num_functions);
+       state->program.functions[state->program.num_functions - 1] = ref;
+
+       module->functions = realloc(module->functions, sizeof *module->functions * ++module->num_functions);
+       module->functions[module->num_functions - 1] = (FunctionLink) {
+               .name = strdup(name),
+               .ref = ref,
+       };
+
+       return ref;
+}
+
+static UwUVMFunction *resolve_function(LoadState *state, Module *caller_module, const char *full_name)
+{
+       size_t len = strlen(full_name);
+
+       const char *fnname;
+       for (fnname = &full_name[len - 1]; *fnname != ':' && fnname > full_name; fnname--)
+               ;
+
+       if (*fnname == ':')
+               fnname++;
+
+       if (*fnname == '\0')
+               error("error: empty function name\n");
+
+       Module *callee_module;
+
+       if (fnname == full_name) {
+               callee_module = caller_module;
+       } else {
+               const char *caller_path = caller_module->environment;
+               const char *callee_name = full_name;
+
+               if (*callee_name == ':') {
+                       caller_path = state->std_path;
+                       callee_name++;
+               }
+
+               size_t path_len = fnname - callee_name;
+               char callee_path[path_len];
+
+               for (size_t i = 0; i < path_len; i++)
+                       callee_path[i] = (i == path_len - 1) ? '\0'
+                               : (callee_name[i] == ':') ? '/'
+                               : callee_name[i];
+
+               callee_module = require_module(state, asprintf_wrapper("%s/%s", caller_path, callee_path));
+       }
+
+       return require_function(state, callee_module, fnname);
+}
+
+static void translate_expression(LoadState *state, Module *module, UwUVMExpression *vm_expr, ParseExpression *parse_expr)
+{
+       UwUVMFunction *vm_function;
+
+       if (parse_expr->type == EX_FNNAME || parse_expr->type == EX_FNCALL) {
+               vm_function = resolve_function(state, module, parse_expr->value.str_value);
+               free(parse_expr->value.str_value);
+       }
+
+       switch (vm_expr->type = parse_expr->type) {
+               case EX_INTLIT:
+               case EX_ARGNUM:
+                       vm_expr->value.int_value = parse_expr->value.int_value;
+                       break;
+
+               case EX_STRLIT:
+                       vm_expr->value.str_value = parse_expr->value.str_value;
+                       break;
+
+               case EX_FNNAME:
+                       vm_expr->value.ref_value = vm_function;
+                       break;
+
+               case EX_FNCALL:
+                       vm_expr->value.cll_value.function = vm_function;
+                       vm_expr->value.cll_value.args = malloc(sizeof(UwUVMExpression) * parse_expr->num_children);
+                       vm_expr->value.cll_value.num_args = parse_expr->num_children;
+
+                       for (size_t i = 0; i < parse_expr->num_children; i++)
+                               translate_expression(state, module, &vm_expr->value.cll_value.args[i], parse_expr->children[i]);
+
+                       if (parse_expr->children)
+                               free(parse_expr->children);
+                       break;
+
+               default:
+                       break;
+       }
+
+       free(parse_expr);
+}
+
+static void load_functions(LoadState *state, Module *module)
+{
+       for (; module->loaded_functions < module->num_functions; module->loaded_functions++) {
+               FunctionLink *link = &module->functions[module->loaded_functions];
+
+               if (module->type == MODULE_PLAIN) {
+                       ParseFunction **function = NULL;
+
+                       for (size_t i = 0; i < module->handle.ast.num_functions; i++) {
+                               ParseFunction **fn = &module->handle.ast.functions[i];
+
+                               if (*fn && strcmp((*fn)->name, link->name) == 0) {
+                                       function = fn;
+                                       break;
+                               }
+                       }
+
+                       if (function) {
+                               translate_expression(state, module, link->ref->value.plain = malloc(sizeof(UwUVMExpression)), (*function)->expression);
+                               free((*function)->name);
+                               free(*function);
+
+                               *function = NULL;
+                       } else {
+                               error("error: no function %s in module %s\n", link->name, module->filename);
+                       }
+               } else {
+                       char *symbol = asprintf_wrapper("uwu_%s", link->name);
+                       link->ref->value.native = dlsym(module->handle.lib, symbol);
+
+                       char *err = dlerror();
+                       if (err)
+                               error("library error: %s\n", err);
+
+                       free(symbol);
+               }
+       }
+}
+
+static void free_expression(ParseExpression *expr)
+{
+       if (expr->type == EX_FNCALL) {
+               for (size_t i = 0; i < expr->num_children; i++)
+                       free_expression(expr->children[i]);
+
+               if (expr->children)
+                       free(expr->children);
+       }
+
+       if (expr->type != EX_INTLIT && expr->type != EX_ARGNUM)
+               free(expr->value.str_value);
+
+       free(expr);
+}
+
+Program load_program(const char *progname, const char *modname)
+{
+       char *prog_dirname = dirname_wrapper(progname);
+       char *api_path = asprintf_wrapper("%s/api/api.so", prog_dirname);
+
+       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,
+                       .functions = NULL,
+                       .num_functions = 0,
+                       .libraries = NULL,
+                       .num_libraries = 0,
+               },
+       };
+
+       free(prog_dirname);
+       free(api_path);
+
+       state.program.main_function = require_function(&state, require_module(&state, strdup(modname)), "main");
+
+       while (true) {
+               bool fully_loaded = true;
+
+               for (size_t i = 0; i < state.num_modules; i++) {
+                       Module *module = state.modules[i];
+
+#if DEBUG
+                       printf("%s %lu/%lu\n", module->filename, module->loaded_functions, module->num_functions);
+#endif
+
+                       if (module->loaded_functions < module->num_functions) {
+                               fully_loaded = false;
+                               load_functions(&state, module);
+                       }
+               }
+
+               if (fully_loaded)
+                       break;
+       }
+
+       free(state.std_path);
+
+       for (size_t i = 0; i < state.num_modules; i++) {
+               Module *module = state.modules[i];
+
+               free(module->path);
+               free(module->filename);
+               free(module->environment);
+
+               for (size_t f = 0; f < module->num_functions; f++)
+                       free(module->functions[f].name);
+
+               free(module->functions);
+
+               if (module->type == MODULE_PLAIN) {
+                       for (size_t f = 0; f < module->handle.ast.num_functions; f++) {
+                               ParseFunction *function = module->handle.ast.functions[f];
+
+                               if (function) {
+                                       free_expression(function->expression);
+                                       free(function->name);
+                                       free(function);
+                               }
+                       }
+
+                       if (module->handle.ast.functions)
+                               free(module->handle.ast.functions);
+               }
+
+               free(module);
+       }
+
+       free(state.modules);
+
+       return state.program;
+}
diff --git a/src/load.h b/src/load.h
new file mode 100644 (file)
index 0000000..5d6b00e
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _LOAD_H_
+#define _LOAD_H_
+
+#include <stddef.h>
+#include "api/vm.h"
+
+typedef struct
+{
+       void *api_library;
+       UwUVMFunction *main_function;
+       UwUVMFunction     **functions;
+       size_t          num_functions;
+       void     **libraries;
+       size_t num_libraries;
+} Program;
+
+Program load_program(const char *progname, const char *modname);
+
+#endif
index 60c22babbfaa71293e75def77c5bcbc0376f8438..2a29d809b62910bcb2819c5efe57ac4cb761db0d 100644 (file)
@@ -1,56 +1,11 @@
-#include "err.h"
-#include "vm.h"
+#include "common/err.h"
+#include "run.h"
 
 int main(int argc, char *argv[])
 {
        if (argc < 2)
                error("usage: %s <module>\n", argv[0]);
 
-       vm_run_file(argv[0], argv[1]);
+       run_module(argv[0], argv[1], argc > 2 ? (size_t) argc - 2 : 0, &argv[2]);
        return 0;
 }
-
-/*
-
-0123
-"asd"
-$arg
-&fnname
-func(asd)
-
-:int:add
-:str:cat
-:boo:and
-:arr:arr
-:set:set
-
-integer::add()
-integer::sub()
-integer::mul()
-integer::div()
-integer::mod()
-integer::pow()
-
-string::concat()
-string::split()
-string::find()
-
-array::array()
-array::select()
-array::insert()
-array::length()
-array::reduce()
-array::map()
-
-set::set()
-set::pair()
-set::select()
-set::insert()
-set::remove()
-set::contains()
-
-boolean::and()
-boolean::or()
-boolean::xor()
-
-*/
index c8b430d4963f52698b6f38caa62c77d6c3d48c11..ed09de9c00a3927608bd46afd7e5be9960772f4a 100644 (file)
@@ -1,7 +1,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
-#include "err.h"
+#include "common/err.h"
 #include "parse.h"
 
 #define DEBUG 0
index 7aca6afb03c8581bef0f245c27b8655f8df43eeb..46f454282e8f8bceb30eef4cb8c71c67746eeb57 100644 (file)
@@ -3,11 +3,11 @@
 
 #include <stddef.h>
 #include <stdbool.h>
-#include "expression.h"
+#include "api/vm.h"
 
 typedef struct ParseExpression
 {
-       ExpressionType type;
+       UwUVMExpressionType type;
        union
        {
                int   int_value;
diff --git a/src/run.c b/src/run.c
new file mode 100644 (file)
index 0000000..7733c8d
--- /dev/null
+++ b/src/run.c
@@ -0,0 +1,74 @@
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "common/err.h"
+#include "load.h"
+#include "run.h"
+
+static void free_expression(UwUVMExpression *expr)
+{
+       if (expr->type == EX_FNCALL) {
+               for (size_t i = 0; i < expr->value.cll_value.num_args; i++)
+                       free_expression(&expr->value.cll_value.args[i]);
+
+               free(expr->value.cll_value.args);
+       }
+
+       if (expr->type == EX_STRLIT)
+               free(expr->value.str_value);
+}
+
+void run_module(const char *progname, const char *modname, size_t num_args, char *args[])
+{
+       (void) num_args;
+       (void) args;
+
+       Program program = load_program(progname, modname);
+
+       UwUVMValue (*uwuvm_call_function)(UwUVMFunction *, size_t, UwUVMExpression *, UwUVMArgs *) = dlsym(program.api_library, "uwuvm_call_function");
+       char      *(*uwuvm_print_value  )(UwUVMValue                                             ) = dlsym(program.api_library, "uwuvm_print_value"  );
+       void       (*uwuvm_delet_value  )(UwUVMValue                                             ) = dlsym(program.api_library, "uwuvm_delet_value"  );
+
+       char *err = dlerror();
+       if (err)
+               error("library error: %s\n", err);
+
+       UwUVMExpression arg_expressions[num_args];
+
+       for (size_t i = 0; i < num_args; i++)
+               arg_expressions[i] = (UwUVMExpression) {
+                       .type = EX_STRLIT,
+                       .value = {
+                               .str_value = args[i],
+                       },
+               };
+
+       UwUVMValue result = uwuvm_call_function(program.main_function, num_args, arg_expressions, NULL);
+
+       char *str = uwuvm_print_value(result);
+       printf("%s\n", str);
+       free(str);
+
+       uwuvm_delet_value(result);
+
+       for (size_t i = 0; i < program.num_functions; i++) {
+               UwUVMFunction *function = program.functions[i];
+
+               if (function->type == MODULE_PLAIN) {
+                       free_expression(function->value.plain);
+                       free(function->value.plain);
+               }
+
+               free(function);
+       }
+
+       free(program.functions);
+
+       for (size_t i = 0; i < program.num_libraries; i++)
+               dlclose(program.libraries[i]);
+
+       if (program.libraries)
+               free(program.libraries);
+
+       dlclose(program.api_library);
+}
diff --git a/src/run.h b/src/run.h
new file mode 100644 (file)
index 0000000..010dec0
--- /dev/null
+++ b/src/run.h
@@ -0,0 +1,8 @@
+#ifndef _RUN_H_
+#define _RUN_H_
+
+#include <stddef.h>
+
+void run_module(const char *progname, const char *modname, size_t num_args, char *args[]);
+
+#endif
diff --git a/src/util.h b/src/util.h
deleted file mode 100644 (file)
index b0baa37..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _UTIL_H_
-#define _UTIL_H_
-
-#include <stdio.h>
-#include <stdarg.h>
-
-static inline char *asprintf_wrapper(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       char *ptr;
-       vasprintf(&ptr, format, args);
-       va_end(args);
-       return ptr;
-}
-
-#endif
diff --git a/src/vm.c b/src/vm.c
deleted file mode 100644 (file)
index 8b1b13a..0000000
--- a/src/vm.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <dlfcn.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "collect.h"
-#include "vm.h"
-
-static void free_expression(UwUVMExpression *expr)
-{
-       if (expr->type == EX_FNCALL) {
-               for (size_t i = 0; i < expr->value.cll_value.num_args; i++)
-                       free_expression(&expr->value.cll_value.args[i]);
-
-               free(expr->value.cll_value.args);
-       }
-
-       if (expr->type == EX_STRLIT)
-               free(expr->value.str_value);
-}
-
-void vm_run_file(const char *progname, const char *modname)
-{
-       UwUVMProgram program = create_program(progname, modname);
-       UwUVMValue result = ((UwUVMValue (*)(UwUVMFunction *, size_t, UwUVMExpression *, UwUVMArgs *)) dlsym(program.api_library, "uwuvm_call_function"))(program.main_function, 0, NULL, NULL);
-
-       char *str = ((char *(*)(UwUVMValue)) dlsym(program.api_library, "uwuvm_print_value"))(result);
-
-       printf("%s\n", str);
-       free(str);
-
-       ((void (*)(UwUVMValue)) dlsym(program.api_library, "uwuvm_delet_value"))(result);
-
-       for (size_t i = 0; i < program.num_functions; i++) {
-               UwUVMFunction *function = program.functions[i];
-
-               if (function->type == MODULE_PLAIN) {
-                       free_expression(function->value.plain);
-                       free(function->value.plain);
-               }
-
-               free(function);
-       }
-
-       free(program.functions);
-
-       for (size_t i = 0; i < program.num_libraries; i++)
-               dlclose(program.libraries[i]);
-
-       if (program.libraries)
-               free(program.libraries);
-
-       dlclose(program.api_library);
-}
diff --git a/src/vm.h b/src/vm.h
deleted file mode 100644 (file)
index 5e23c8b..0000000
--- a/src/vm.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _VM_H_
-#define _VM_H_
-
-void vm_run_file(const char *progname, const char *modname);
-
-#endif
index 4386dc3fb9588b1335e026fd9b259c9879034099..349e1c9fcc76d9c8093f34c874fa1746c884f5a8 100644 (file)
@@ -1,10 +1,9 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include "../src/err.h"
-#include "../api/vm.h"
-#include "../api/util.h"
-#include "../api/bool.h"
-
+#include "common/err.h"
+#include "api/vm.h"
+#include "api/util.h"
+#include "api/bool.h"
 
 static inline bool get_bool_arg(UwUVMArgs *args, size_t i)
 {
index 6857f26fea4dc731a7d527dad11ed3a10b22af9d..22af320ee93e760a961b2ce2dcc32c4ee8a55737 100644 (file)
--- a/std/int.c
+++ b/std/int.c
@@ -1,10 +1,10 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include "../src/err.h"
-#include "../api/vm.h"
-#include "../api/int.h"
-#include "../api/bool.h"
-#include "../api/util.h"
+#include "common/err.h"
+#include "api/vm.h"
+#include "api/int.h"
+#include "api/bool.h"
+#include "api/util.h"
 
 typedef enum
 {
index 599e3d42d4e91dc64f5c5cc7eb8eee9c5180f4e8..93172eb7c8de66d92a2e0ee120d988d5f5fd151e 100644 (file)
--- a/std/nil.c
+++ b/std/nil.c
@@ -1,6 +1,6 @@
-#include "../src/err.h"
-#include "../api/nil.h"
-#include "../api/util.h"
+#include "common/err.h"
+#include "api/nil.h"
+#include "api/util.h"
 
 UwUVMValue uwu_nil(UwUVMArgs *args)
 {
index f82bb5030ad213ef9aa47cbdc4a36fa76890254f..62c0a5289bfd9207753d2302eb10f9e76e5db5fc 100644 (file)
--- a/std/ref.c
+++ b/std/ref.c
@@ -1,6 +1,6 @@
-#include "../src/err.h"
-#include "../api/ref.h"
-#include "../api/util.h"
+#include "common/err.h"
+#include "api/ref.h"
+#include "api/util.h"
 
 UwUVMValue uwu_call(UwUVMArgs *args)
 {
index 953e8c086ece3c07e74ee9e4ed99fa8cd4185598..a0e4edd5d43518cb9d30df37885a1551f4647ec3 100644 (file)
--- a/std/str.c
+++ b/std/str.c
@@ -1,8 +1,8 @@
 #include <string.h>
 #include <stdlib.h>
-#include "../api/vm.h"
-#include "../api/str.h"
-#include "../api/util.h"
+#include "api/vm.h"
+#include "api/str.h"
+#include "api/util.h"
 
 UwUVMValue uwu_cat(UwUVMArgs *args)
 {