From: Brendan Hansen Date: Mon, 28 Feb 2022 01:50:34 +0000 (-0600) Subject: added "#load_all" to load all onyx files in a folder X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=5a5b94f2b2a1ee23aa0025c5595ce299a567600c;p=onyx.git added "#load_all" to load all onyx files in a folder --- diff --git a/include/astnodes.h b/include/astnodes.h index 02551a8a..068bafe7 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -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, diff --git a/include/bh.h b/include/bh.h index 66e86433..a123b7d3 100644 --- a/include/bh.h +++ b/include/bh.h @@ -20,6 +20,7 @@ #include #include #include + #include #endif #include @@ -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; ihndl = 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 diff --git a/src/astnodes.c b/src/astnodes.c index e983062c..d354d520 100644 --- a/src/astnodes.c +++ b/src/astnodes.c @@ -7,6 +7,7 @@ static const char* ast_node_names[] = { "PACKAGE", "INCLUDE FILE", "INCLUDE FOLDER", + "INCLUDE ALL IN FOLDER", "INCLUDE LIBRARY PATH", "MEMORY RESERVATION", diff --git a/src/clone.c b/src/clone.c index d7b7d26c..324ddee3 100644 --- a/src/clone.c +++ b/src/clone.c @@ -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); diff --git a/src/entities.c b/src/entities.c index db5dbcd8..c50dd465 100644 --- a/src/entities.c +++ b/src/entities.c @@ -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; diff --git a/src/onyx.c b/src/onyx.c index a28a295a..c3611956 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -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); diff --git a/src/parser.c b/src/parser.c index 342b5564..9e90474b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -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;