__file_open_impl :: (path: str, mode: os.OpenMode, out_handle: ^FileData.Handle) -> os.FileError ---
__file_close :: (fd: FileData) -> os.FileError ---
+ __file_stat :: (path: str, stat: ^os.FileStat) -> bool ---
__file_exists :: (path: str) -> bool ---
__file_remove :: (path: str) -> bool ---
__file_rename :: (old_path: str, new_path: str) -> bool ---
Directory :: fs.DirectoryData;
DirectoryEntry :: struct {
- // Most of these types were stollen directly from
- // man readdir(3), and the most reasonable types
- // were used for Windows.
- Type :: enum {
- Unknown :: 0x00;
- Block :: 0x01;
- Char :: 0x02;
- Directory :: 0x03;
- RegularFile :: 0x04;
- SymLink :: 0x05;
- Other :: 0x06;
- }
-
- type : Type;
+ type : FileType;
identifier : u32;
name_length : u32;
name_data : [256] u8;
use data : fs.FileData;
}
+// Most of these types were stollen directly from
+// man readdir(3), and the most reasonable types
+// were used for Windows.
+FileType :: enum {
+ Unknown :: 0x00;
+ Block :: 0x01;
+ Char :: 0x02;
+ Directory :: 0x03;
+ RegularFile :: 0x04;
+ SymLink :: 0x05;
+ Other :: 0x06;
+}
+
+//
+// This is fairly minimal for right now.
+FileStat :: struct {
+ size: i64;
+ type: FileType;
+}
+
file_exists :: fs.__file_exists
+file_stat :: fs.__file_stat
remove_file :: fs.__file_remove
rename_file :: fs.__file_rename
return .{ c, next, close_context };
}
+is_file :: (path: str) -> bool {
+ s: FileStat;
+ if !file_stat(path, ^s) do return false;
+ return s.type == .RegularFile;
+}
+is_directory :: (path: str) -> bool {
+ s: FileStat;
+ if !file_stat(path, ^s) do return false;
+ return s.type == .Directory;
+}
file_logger_open :: (filename: str, allocator := context.allocator) -> Logger {
return strarr[0 .. delim_count + 1];
}
+
+//
+// Splits a string into two parts, divided by the
+// first instance of the provided character. Either
+// string can be empty if the first instance of the
+// character occurs at the very beginning or end of
+// the string, or if it does not occur at all.
+//
+bisect :: (s: str, c: u8) -> (str, str) {
+ index := index_of(s, c);
+ if index == -1 {
+ return s, "";
+ }
+
+ return s[0 .. index], s[index+1 .. s.length];
+}
+
return .None;
}
+__file_stat :: (path: str, out: ^os.FileStat) -> bool {
+ fs: wasi.FileStat;
+
+ exists := false;
+ for .[3, 4] { // Trying both preopened directories
+ err := wasi.path_filestat_get(it, .SymLinkFollow, path, ^fs);
+ if err == .Success {
+ exists = true;
+ out.size = ~~ fs.size;
+
+ switch fs.filetype {
+ case .RegularFile do out.type = .RegularFile;
+ case .Directory do out.type = .Directory;
+ case .SymLink do out.type = .SymLink;
+ case #default do out.type = .Unknown;
+ }
+ }
+ }
+
+ return exists;
+}
+
__file_exists :: (path: str) -> bool {
fs: wasi.FileStat;
isize line_count;
} bh_file_contents;
+
+#define BH_FILE_TYPE_DIRECTORY 3
+#define BH_FILE_TYPE_FILE 4
+#define BH_FILE_TYPE_LINK 5
+typedef struct bh_file_stats {
+ isize size;
+ u32 file_type;
+} bh_file_stats;
+
bh_file_error bh_file_get_standard(bh_file* file, bh_file_standard stand);
bh_file_error bh_file_create(bh_file* file, char const* filename);
i32 bh_file_write(bh_file* file, void* buffer, isize buff_size);
void bh_file_flush(bh_file* file);
i64 bh_file_size(bh_file* file);
+b32 bh_file_stat(char const* filename, bh_file_stats* stat);
b32 bh_file_exists(char const* filename);
b32 bh_file_remove(char const* filename);
char* bh_path_get_full_name(char const* filename, bh_allocator a);
return 1;
}
+b32 bh_file_stat(char const* filename, bh_file_stats* out) {
+ struct stat s;
+ if (stat(filename, &s) == -1) {
+ return 0;
+ }
+
+ out->size = s.st_size;
+
+ if ((s.st_mode & S_IFMT) == S_IFDIR) out->file_type = BH_FILE_TYPE_DIRECTORY;
+ if ((s.st_mode & S_IFMT) == S_IFREG) out->file_type = BH_FILE_TYPE_FILE;
+ if ((s.st_mode & S_IFMT) == S_IFLNK) out->file_type = BH_FILE_TYPE_LINK;
+
+ return 1;
+}
+
b32 bh_file_exists(char const* filename) {
struct stat s;
return stat(filename, &s) != -1;
b32 hit_unexpected_token : 1;
b32 parse_calls : 1;
+ b32 inside_tag : 1;
} OnyxParser;
const char* onyx_ast_node_kind_string(AstKind kind);
return NULL;
}
+ONYX_DEF(__file_stat, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ char *path_ptr = ONYX_PTR(params->data[0].of.i32);
+ int path_len = params->data[1].of.i32;
+
+ char path[512] = {0};
+ path_len = bh_min(path_len, 511);
+ strncpy(path, path_ptr, path_len);
+ path[path_len] = 0;
+
+ results->data[0] = WASM_I32_VAL(bh_file_stat(path, ONYX_PTR(params->data[2].of.i32)));
+ return NULL;
+}
+
ONYX_DEF(__file_remove, (WASM_I32, WASM_I32), (WASM_I32)) {
char *path_ptr = ONYX_PTR(params->data[0].of.i32);
int path_len = params->data[1].of.i32;
ONYX_FUNC(__file_open_impl)
ONYX_FUNC(__file_close)
ONYX_FUNC(__file_exists)
+ ONYX_FUNC(__file_stat)
ONYX_FUNC(__file_remove)
ONYX_FUNC(__file_seek)
ONYX_FUNC(__file_tell)
}
static void flush_stored_tags(OnyxParser *parser, bh_arr(AstTyped *) *out_arr) {
- if (bh_arr_length(parser->stored_tags) == 0) return;
+ //
+ // When inside_tag is true, no tags will be added to the element.
+ // This happens if you have a something like so,
+ //
+ // #tag "asdf"
+ // #tag handler.{ (x: i32) => x * 2 }
+ // foo :: () { ... }
+ //
+ // In this situation, the inner procedure defined in the second
+ // tag should NOT consume the "asdf" tag.
+ //
+ if (bh_arr_length(parser->stored_tags) == 0 || parser->inside_tag) return;
bh_arr(AstTyped *) arr = *out_arr;
while (parse_possible_directive(parser, "tag")) {
if (meta_tags == NULL) bh_arr_new(global_heap_allocator, meta_tags, 1);
+ parser->inside_tag = 1;
+
do {
AstTyped* expr = parse_expression(parser, 0);
bh_arr_push(meta_tags, expr);
} while (consume_token_if_next(parser, ','));
+
+ parser->inside_tag = 0;
}
member_is_used = consume_token_if_next(parser, Token_Type_Keyword_Use);
return;
}
else if (parse_possible_directive(parser, "tag")) {
+ parser->inside_tag = 1;
+
AstTyped *expr = parse_expression(parser, 0);
bh_arr_push(parser->stored_tags, expr);
+
+ parser->inside_tag = 0;
return;
}
else {