added "#load_all" to load all onyx files in a folder
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 28 Feb 2022 01:50:34 +0000 (19:50 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 28 Feb 2022 01:50:34 +0000 (19:50 -0600)
include/astnodes.h
include/bh.h
src/astnodes.c
src/clone.c
src/entities.c
src/onyx.c
src/parser.c

index 02551a8a1dd4e524546f65f4d567bda00e43200a..068bafe7ab2ceb1d0e8aadf34580bc32d6b028f4 100644 (file)
@@ -124,6 +124,7 @@ typedef enum AstKind {
     Ast_Kind_Package,
     Ast_Kind_Load_File,
     Ast_Kind_Load_Path,
+    Ast_Kind_Load_All,
     Ast_Kind_Library_Path,
     Ast_Kind_Memres,
 
index 66e86433f99a60fee3de509487655313e45edfc6..a123b7d3b8556b77070536abb49f686dad5af56d 100644 (file)
@@ -20,6 +20,7 @@
     #include <errno.h>
     #include <fcntl.h>
     #include <unistd.h>
+    #include <dirent.h>
 #endif
 
 #include <stdlib.h>
@@ -392,6 +393,39 @@ bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file
 bh_file_contents bh_file_read_contents_direct(bh_allocator alloc, const char* filename);
 i32 bh_file_contents_free(bh_file_contents* contents);
 
+
+#ifdef _BH_WINDOWS
+    typedef struct Windows_Directory_Opened {
+        HANDLE hndl;
+        WIN32_FIND_DATAA found_file;
+    } Windows_Directory_Opened;
+
+    typedef Windows_Directory_Opened *bh_dir;
+#else
+    typedef DIR *bh_dir;
+#endif
+
+typedef enum bh_dirent_type {
+    BH_DIRENT_UNKNOWN,
+    BH_DIRENT_BLOCK,
+    BH_DIRENT_CHAR,
+    BH_DIRENT_DIRECTORY,
+    BH_DIRENT_FILE,
+    BH_DIRENT_SYMLINK,
+    BH_DIRENT_OTHER,
+} bh_dirent_type;
+
+typedef struct bh_dirent {
+    bh_dirent_type type;
+    u32 id;
+    u32 name_length;
+    char name[256];
+} bh_dirent;
+
+bh_dir bh_dir_open(char* path);
+b32    bh_dir_read(bh_dir dir, bh_dirent* out);
+void   bh_dir_close(bh_dir dir);
+
 #endif
 
 
@@ -1683,6 +1717,95 @@ char* bh_lookup_file(char* filename, char* relative_to, char *suffix, b32 add_su
     return fn;
 }
 
+
+bh_dir bh_dir_open(char* path) {
+#ifdef _BH_WINDOWS
+    for (int i=0; i<path_len; i++) if (path[i] == '/') path[i] = '\\';
+    strncat(path, "\\*.*", 511);
+
+    Windows_Directory_Opened* dir = malloc(sizeof(Windows_Directory_Opened));
+    dir->hndl = FindFirstFileA(path, &dir->found_file);
+    if (dir->hndl == INVALID_HANDLE_VALUE) {
+        return NULL;
+    }
+
+    return dir;
+#endif
+
+#ifdef _BH_LINUX
+    DIR* dir = opendir(path);
+    return dir;
+#endif
+}
+
+b32 bh_dir_read(bh_dir dir, bh_dirent* out) {
+
+#ifdef _BH_WINDOWS
+    Windows_Directory_Opened* dir = (Windows_Directory_Opened *) params->data[0].of.i64;
+    if (dir == NULL) return 0;
+
+    do {
+        BOOL success = FindNextFileA(dir->hndl, &dir->found_file);
+        if (!success) return 0;
+    } while (!strcmp(dir->found_file.cFileName, ".") || !strcmp(dir->found_file.cFileName, ".."));
+
+    if (out == NULL) return 1;
+
+    out->type = (dir->found_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        ? BH_DIRENT_DIRECTORY : BH_DIRENT_FILE;
+    out->id = 0;
+    out->name_length = strlen(dir->found_file.cFileName);
+    strncpy(out->name, dir->found_file.cFileName, 256);
+
+    return 1;
+#endif
+
+#ifdef _BH_LINUX
+    struct dirent *ent;
+    while (1) {
+        ent = readdir(dir);
+        if (ent == NULL) return 0;
+
+        // Skip the current directory and parent directory
+        if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) break;
+    }
+
+    bh_dirent_type type = 0;
+    switch (ent->d_type) {
+        case DT_UNKNOWN: break;
+        case DT_BLK: type = BH_DIRENT_BLOCK; break;
+        case DT_CHR: type = BH_DIRENT_CHAR; break;
+        case DT_DIR: type = BH_DIRENT_DIRECTORY; break;
+        case DT_LNK: type = BH_DIRENT_SYMLINK; break;
+        case DT_REG: type = BH_DIRENT_FILE; break;
+        default: type = BH_DIRENT_OTHER; break;
+    }
+
+    if (out == NULL) return 1;
+
+    out->type = type;
+    out->id = (u32) ent->d_ino;
+    out->name_length = strlen(ent->d_name);
+    strncpy(out->name, ent->d_name, 256);
+
+    return 1;
+#endif
+}
+
+void bh_dir_close(bh_dir dir) {
+#ifdef _BH_WINDOWS
+    if (dir == NULL) return;
+
+    FindClose(dir->hndl);
+    free(dir);
+#endif
+
+#ifdef _BH_LINUX
+    if (dir == NULL) return;
+    closedir(dir);
+#endif
+}
+
 #undef DIR_SEPARATOR
 
 #endif // ifndef BH_NO_FILE
index e983062cb66094e5120ae0f0c4ddee77449f4137..d354d520e9f43e71e52302aeaaf3c89b948053d4 100644 (file)
@@ -7,6 +7,7 @@ static const char* ast_node_names[] = {
     "PACKAGE",
     "INCLUDE FILE",
     "INCLUDE FOLDER",
+    "INCLUDE ALL IN FOLDER",
     "INCLUDE LIBRARY PATH",
     "MEMORY RESERVATION",
 
index d7b7d26c131cee9d43034a7c191d35c63ff952e4..324ddee390065048e44df1aa4ffb2995f035a51c 100644 (file)
@@ -42,6 +42,7 @@ static inline i32 ast_kind_to_size(AstNode* node) {
         case Ast_Kind_Package: return sizeof(AstPackage);
         case Ast_Kind_Load_File: return sizeof(AstInclude);
         case Ast_Kind_Load_Path: return sizeof(AstInclude);
+        case Ast_Kind_Load_All: return sizeof(AstInclude);
         case Ast_Kind_Memres: return sizeof(AstMemRes);
         case Ast_Kind_Binding: return sizeof(AstBinding);
         case Ast_Kind_Function: return sizeof(AstFunction);
index db5dbcd8d69157ce6f68400c537410d4b701b540..c50dd4650f011c59c3310b59e38e63cb3c598013 100644 (file)
@@ -170,6 +170,7 @@ void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* s
     ent.scope   = scope;
 
     switch (node->kind) {
+        case Ast_Kind_Load_All:
         case Ast_Kind_Load_File: {
             ent.type = Entity_Type_Load_File;
             ent.include = (AstInclude *) node;
index a28a295aba8e353b81e097276be2a46d9a652239..c3611956b702169cc6b24d1803358e7dc5d0ca24 100644 (file)
@@ -339,6 +339,41 @@ static b32 process_load_entity(Entity* ent) {
 
         return process_source_file(formatted_name, include->token->pos);
 
+    } else if (include->kind == Ast_Kind_Load_All) {
+        const char* parent_file = include->token->pos.filename;
+        if (parent_file == NULL) parent_file = ".";
+
+        char* parent_folder = bh_path_get_parent(parent_file, global_scratch_allocator);
+        char folder[512];
+        if (bh_str_starts_with(include->name, "./")) {
+            bh_snprintf(folder, 511, "%s/%s", parent_folder, include->name + 2);
+        } else {
+            bh_snprintf(folder, 511, "%s", include->name);
+        }
+
+        // This does not take into account #load_path'd folders...
+
+        bh_dir dir = bh_dir_open(folder);
+        if (dir == NULL) {
+            onyx_report_error(include->token->pos, Error_Critical, "Could not find folder '%s'.", folder);
+            return 0;
+        }
+
+        bh_dirent entry;
+        b32 success = 1;
+        char fullpath[512];
+        while (bh_dir_read(dir, &entry)) {
+            if (entry.type == BH_DIRENT_FILE && bh_str_ends_with(entry.name, ".onyx")) {
+                bh_snprintf(fullpath, 511, "%s/%s", folder, entry.name);
+                u8* formatted_name = bh_path_get_full_name(fullpath, global_heap_allocator);
+                success = process_source_file(formatted_name, include->token->pos);
+                if (!success) break;
+            }
+        }
+
+        bh_dir_close(dir);
+        return success;
+        
     } else if (include->kind == Ast_Kind_Load_Path) {
         bh_arr_push(context.options->included_folders, include->name);
 
index 342b55647ea9df9951c5583386ceff9d4bf4c368..9e90474b5a43108b6a7a18f36955057778ed817e 100644 (file)
@@ -2984,6 +2984,14 @@ static void parse_top_level_statement(OnyxParser* parser) {
                 ENTITY_SUBMIT(include);
                 return;
             }
+            else if (parse_possible_directive(parser, "load_all")) {
+                AstInclude* include = make_node(AstInclude, Ast_Kind_Load_All);
+                include->token = dir_token;
+                include->name_node = parse_expression(parser, 0);
+
+                ENTITY_SUBMIT(include);
+                return;
+            }
             else if (parse_possible_directive(parser, "load_path")) {
                 AstInclude* include = make_node(AstInclude, Ast_Kind_Load_Path);
                 include->token = dir_token;