Pārlūkot izejas kodu

improve error handling, more fs work

Aurel Bílý 6 gadi atpakaļ
vecāks
revīzija
05aae0e490

+ 69 - 56
libs/uv/uv.ml

@@ -1,3 +1,14 @@
+(* ------------- CONSTANTS ------------------------------------------ *)
+
+let s_IFMT = 0xF000
+let s_IFBLK = 0x6000
+let s_IFCHR = 0x2000
+let s_IFDIR = 0x4000
+let s_IFIFO = 0x1000
+let s_IFLNK = 0xA000
+let s_IFREG = 0x8000
+let s_IFSOCK = 0xC000
+
 (* ------------- TYPES ---------------------------------------------- *)
 
 (* Handle types *)
@@ -70,75 +81,77 @@ type t_stat = {
 	birthtime_nsec: int;
 }
 
-type 'a cb_result =
-	| CbError of string (* error message *)
-	| CbSuccess of 'a
+type 'a uv_result =
+	| UvError of int (* error number *)
+	| UvSuccess of 'a
 
 (* ------------- LOOP ----------------------------------------------- *)
 
-external loop_init : unit -> t_loop = "w_loop_init"
-external loop_close : t_loop -> unit = "w_loop_close"
-external run : t_loop -> int -> bool = "w_run"
-external loop_alive : t_loop -> bool = "w_loop_alive"
+external loop_init : unit -> t_loop uv_result = "w_loop_init"
+external loop_close : t_loop -> unit uv_result = "w_loop_close"
+external run : t_loop -> int -> bool uv_result = "w_run"
+external loop_alive : t_loop -> bool uv_result = "w_loop_alive"
 
 (* ------------- FILESYSTEM ----------------------------------------- *)
 
-type fs_cb = unit cb_result -> unit
-type fs_cb_bytes = string cb_result -> unit
-type fs_cb_path = string cb_result -> unit
-type fs_cb_file = t_file cb_result -> unit
-type fs_cb_int = int cb_result -> unit
-type fs_cb_stat= t_stat cb_result -> unit
-type fs_cb_scandir = (string * int) list cb_result -> unit
+type fs_cb = unit uv_result -> unit
+type fs_cb_bytes = string uv_result -> unit
+type fs_cb_path = string uv_result -> unit
+type fs_cb_file = t_file uv_result -> unit
+type fs_cb_int = int uv_result -> unit
+type fs_cb_stat= t_stat uv_result -> unit
+type fs_cb_scandir = (string * int) list uv_result -> unit
 
+external fs_access : t_loop -> string -> int -> fs_cb -> unit = "w_fs_access"
+external fs_chmod : t_loop -> string -> int -> fs_cb -> unit = "w_fs_chmod"
+external fs_chown : t_loop -> string -> int -> int -> fs_cb -> unit = "w_fs_chown"
 external fs_close : t_loop -> t_file -> fs_cb -> unit = "w_fs_close"
-external fs_open : t_loop -> string -> int -> int -> fs_cb_file -> unit = "w_fs_open"
-external fs_unlink : t_loop -> string -> fs_cb -> unit = "w_fs_unlink"
-external fs_mkdir : t_loop -> string -> int -> fs_cb -> unit = "w_fs_mkdir"
-external fs_mkdtemp : t_loop -> string -> fs_cb_path -> unit = "w_fs_mkdtemp"
-external fs_rmdir : t_loop -> string -> fs_cb -> unit = "w_fs_rmdir"
-external fs_scandir : t_loop -> string -> int -> fs_cb_scandir -> unit = "w_fs_scandir"
-external fs_stat : t_loop -> string -> fs_cb_stat -> unit = "w_fs_stat"
+external fs_fchmod : t_loop -> t_file -> int -> fs_cb -> unit = "w_fs_fchmod"
+external fs_fchown : t_loop -> t_file -> int -> int -> fs_cb -> unit = "w_fs_fchown"
+external fs_fdatasync : t_loop -> t_file -> fs_cb -> unit = "w_fs_fdatasync"
 external fs_fstat : t_loop -> t_file -> fs_cb_stat -> unit = "w_fs_fstat"
-external fs_lstat : t_loop -> string -> fs_cb_stat -> unit = "w_fs_lstat"
-external fs_rename : t_loop -> string -> string -> fs_cb -> unit = "w_fs_rename"
 external fs_fsync : t_loop -> t_file -> fs_cb -> unit = "w_fs_fsync"
-external fs_fdatasync : t_loop -> t_file -> fs_cb -> unit = "w_fs_fdatasync"
 external fs_ftruncate : t_loop -> t_file -> int64 -> fs_cb -> unit = "w_fs_ftruncate"
-external fs_access : t_loop -> string -> int -> fs_cb -> unit = "w_fs_access"
-external fs_chmod : t_loop -> string -> int -> fs_cb -> unit = "w_fs_chmod"
-external fs_fchmod : t_loop -> t_file -> int -> fs_cb -> unit = "w_fs_fchmod"
-external fs_utime : t_loop -> string -> float -> float -> fs_cb -> unit = "w_fs_utime"
 external fs_futime : t_loop -> t_file -> float -> float -> fs_cb -> unit = "w_fs_futime"
 external fs_link : t_loop -> string -> string -> fs_cb -> unit = "w_fs_link"
-external fs_symlink : t_loop -> string -> string -> int -> fs_cb -> unit = "w_fs_symlink"
+external fs_lstat : t_loop -> string -> fs_cb_stat -> unit = "w_fs_lstat"
+external fs_mkdir : t_loop -> string -> int -> fs_cb -> unit = "w_fs_mkdir"
+external fs_mkdtemp : t_loop -> string -> fs_cb_path -> unit = "w_fs_mkdtemp"
+external fs_open : t_loop -> string -> int -> int -> fs_cb_file -> unit = "w_fs_open"
+external fs_read : t_loop -> t_file -> bytes -> int -> int -> int -> fs_cb_int -> unit = "w_fs_read_bytecode" "w_fs_read"
 external fs_readlink : t_loop -> string -> fs_cb_bytes -> unit = "w_fs_readlink"
 external fs_realpath : t_loop -> string -> fs_cb_bytes -> unit = "w_fs_realpath"
-external fs_chown : t_loop -> string -> int -> int -> fs_cb -> unit = "w_fs_chown"
-external fs_fchown : t_loop -> t_file -> int -> int -> fs_cb -> unit = "w_fs_fchown"
+external fs_rename : t_loop -> string -> string -> fs_cb -> unit = "w_fs_rename"
+external fs_rmdir : t_loop -> string -> fs_cb -> unit = "w_fs_rmdir"
+external fs_scandir : t_loop -> string -> int -> fs_cb_scandir -> unit = "w_fs_scandir"
+external fs_stat : t_loop -> string -> fs_cb_stat -> unit = "w_fs_stat"
+external fs_symlink : t_loop -> string -> string -> int -> fs_cb -> unit = "w_fs_symlink"
+external fs_unlink : t_loop -> string -> fs_cb -> unit = "w_fs_unlink"
+external fs_utime : t_loop -> string -> float -> float -> fs_cb -> unit = "w_fs_utime"
 
-external fs_close_sync : t_loop -> t_file -> unit = "w_fs_close_sync"
-external fs_open_sync : t_loop -> string -> int -> int -> t_file = "w_fs_open_sync"
-external fs_unlink_sync : t_loop -> string -> unit = "w_fs_unlink_sync"
-external fs_mkdir_sync : t_loop -> string -> int -> unit = "w_fs_mkdir_sync"
-external fs_mkdtemp_sync : t_loop -> string -> string = "w_fs_mkdtemp_sync"
-external fs_rmdir_sync : t_loop -> string -> unit = "w_fs_rmdir_sync"
-external fs_scandir_sync : t_loop -> string -> int -> (string * int) list = "w_fs_scandir_sync"
-external fs_stat_sync : t_loop -> string -> t_stat = "w_fs_stat_sync"
-external fs_fstat_sync : t_loop -> t_file -> t_stat = "w_fs_fstat_sync"
-external fs_lstat_sync : t_loop -> string -> t_stat = "w_fs_lstat_sync"
-external fs_rename_sync : t_loop -> string -> string -> unit = "w_fs_rename_sync"
-external fs_fsync_sync : t_loop -> t_file -> unit = "w_fs_fsync_sync"
-external fs_fdatasync_sync : t_loop -> t_file -> unit = "w_fs_fdatasync_sync"
-external fs_ftruncate_sync : t_loop -> t_file -> int64 -> unit = "w_fs_ftruncate_sync"
-external fs_access_sync : t_loop -> string -> int -> unit = "w_fs_access_sync"
-external fs_chmod_sync : t_loop -> string -> int -> unit = "w_fs_chmod_sync"
-external fs_fchmod_sync : t_loop -> t_file -> int -> unit = "w_fs_fchmod_sync"
-external fs_utime_sync : t_loop -> string -> float -> float -> unit = "w_fs_utime_sync"
-external fs_futime_sync : t_loop -> t_file -> float -> float -> unit = "w_fs_futime_sync"
-external fs_link_sync : t_loop -> string -> string -> unit = "w_fs_link_sync"
-external fs_symlink_sync : t_loop -> string -> string -> int -> unit = "w_fs_symlink_sync"
-external fs_readlink_sync : t_loop -> string -> string = "w_fs_readlink_sync"
-external fs_realpath_sync : t_loop -> string -> string = "w_fs_realpath_sync"
-external fs_chown_sync : t_loop -> string -> int -> int -> unit = "w_fs_chown_sync"
-external fs_fchown_sync : t_loop -> t_file -> int -> int -> unit = "w_fs_fchown_sync"
+external fs_access_sync : t_loop -> string -> int -> unit uv_result = "w_fs_access_sync"
+external fs_chmod_sync : t_loop -> string -> int -> unit uv_result = "w_fs_chmod_sync"
+external fs_chown_sync : t_loop -> string -> int -> int -> unit uv_result = "w_fs_chown_sync"
+external fs_close_sync : t_loop -> t_file -> unit uv_result = "w_fs_close_sync"
+external fs_fchmod_sync : t_loop -> t_file -> int -> unit uv_result = "w_fs_fchmod_sync"
+external fs_fchown_sync : t_loop -> t_file -> int -> int -> unit uv_result = "w_fs_fchown_sync"
+external fs_fdatasync_sync : t_loop -> t_file -> unit uv_result = "w_fs_fdatasync_sync"
+external fs_fstat_sync : t_loop -> t_file -> t_stat uv_result = "w_fs_fstat_sync"
+external fs_fsync_sync : t_loop -> t_file -> unit uv_result = "w_fs_fsync_sync"
+external fs_ftruncate_sync : t_loop -> t_file -> int64 -> unit uv_result = "w_fs_ftruncate_sync"
+external fs_futime_sync : t_loop -> t_file -> float -> float -> unit uv_result = "w_fs_futime_sync"
+external fs_link_sync : t_loop -> string -> string -> unit uv_result = "w_fs_link_sync"
+external fs_lstat_sync : t_loop -> string -> t_stat uv_result = "w_fs_lstat_sync"
+external fs_mkdir_sync : t_loop -> string -> int -> unit uv_result = "w_fs_mkdir_sync"
+external fs_mkdtemp_sync : t_loop -> string -> string uv_result = "w_fs_mkdtemp_sync"
+external fs_open_sync : t_loop -> string -> int -> int -> t_file uv_result = "w_fs_open_sync"
+external fs_read_sync : t_loop -> t_file -> bytes -> int -> int -> int -> int uv_result = "w_fs_read_sync_bytecode" "w_fs_read_sync"
+external fs_readlink_sync : t_loop -> string -> string uv_result = "w_fs_readlink_sync"
+external fs_realpath_sync : t_loop -> string -> string uv_result = "w_fs_realpath_sync"
+external fs_rename_sync : t_loop -> string -> string -> unit uv_result = "w_fs_rename_sync"
+external fs_rmdir_sync : t_loop -> string -> unit uv_result = "w_fs_rmdir_sync"
+external fs_scandir_sync : t_loop -> string -> int -> (string * int) list uv_result = "w_fs_scandir_sync"
+external fs_stat_sync : t_loop -> string -> t_stat uv_result = "w_fs_stat_sync"
+external fs_symlink_sync : t_loop -> string -> string -> int -> unit uv_result = "w_fs_symlink_sync"
+external fs_unlink_sync : t_loop -> string -> unit uv_result = "w_fs_unlink_sync"
+external fs_utime_sync : t_loop -> string -> float -> float -> unit uv_result = "w_fs_utime_sync"

+ 64 - 27
libs/uv/uv_stubs.c

@@ -25,29 +25,47 @@
 
 // ------------- ERROR HANDLING -------------------------------------
 
+#define UV_ERROR(errno) do { \
+		value res = caml_alloc(1, 0); \
+		Field(res, 0) = Val_int(errno); \
+		CAMLreturn(res); \
+	} while (0)
+
+#define UV_SUCCESS_UNIT do { \
+		value res = caml_alloc(1, 1); \
+		Field(res, 0) = Val_unit; \
+		CAMLreturn(res); \
+	} while (0)
+
+#define UV_SUCCESS(success_value) do { \
+		value res = caml_alloc(1, 1); \
+		Field(res, 0) = (value)(success_value); \
+		CAMLreturn(res); \
+	} while (0)
+
 #define UV_ALLOC_CHECK(var, type) \
 	type *var = UV_ALLOC(type); \
 	if (var == NULL) { \
-		caml_failwith("malloc " #type " failed"); \
+		UV_ERROR(0); \
 	} else {}
 #define UV_ALLOC_CHECK_C(var, type, cleanup) \
 	type *var = UV_ALLOC(type); \
 	if (var == NULL) { \
 		cleanup; \
-		caml_failwith("malloc " #type " failed"); \
+		UV_ERROR(0); \
 	} else {}
 // TODO: proper exceptions for libuv errors
 #define UV_ERROR_CHECK(expr) do { \
 		int __tmp_result = expr; \
 		if (__tmp_result < 0) { \
-			caml_failwith(strdup(uv_strerror(__tmp_result))); \
+			UV_ERROR(__tmp_result); \
 		} \
 	} while (0)
 #define UV_ERROR_CHECK_C(expr, cleanup) do { \
 		int __tmp_result = expr; \
 		if (__tmp_result < 0) { \
 			cleanup; \
-			caml_failwith(strdup(uv_strerror(__tmp_result))); \
+			UV_ERROR(__tmp_result); \
 		} \
 	} while (0)
 
@@ -57,30 +75,30 @@ CAMLprim value w_loop_init(value unit) {
 	CAMLparam1(unit);
 	UV_ALLOC_CHECK(loop, uv_loop_t);
 	UV_ERROR_CHECK_C(uv_loop_init(loop), free(loop));
-	CAMLreturn((value)loop);
+	UV_SUCCESS(loop);
 }
 
 CAMLprim value w_loop_close(value loop) {
 	CAMLparam1(loop);
 	UV_ERROR_CHECK(uv_loop_close((uv_loop_t *)loop));
 	free((uv_loop_t *)loop);
-	CAMLreturn(Val_unit);
+	UV_SUCCESS_UNIT;
 }
 
 CAMLprim value w_run(value loop, value mode) {
 	CAMLparam2(loop, mode);
-	CAMLreturn(Val_bool(uv_run((uv_loop_t *)loop, (uv_run_mode)mode) == 0));
+	UV_SUCCESS(Val_bool(uv_run((uv_loop_t *)loop, (uv_run_mode)Int_val(mode)) == 0));
 }
 
 CAMLprim value w_loop_alive(value loop) {
 	CAMLparam1(loop);
-	CAMLreturn(Val_bool(uv_loop_alive((uv_loop_t *)loop) != 0));
+	UV_SUCCESS(Val_bool(uv_loop_alive((uv_loop_t *)loop) != 0));
 }
 
 CAMLprim value w_stop(value loop) {
 	CAMLparam1(loop);
 	uv_stop((uv_loop_t *)loop);
-	CAMLreturn(Val_unit);
+	UV_SUCCESS_UNIT;
 }
 
 // ------------- FILESYSTEM -----------------------------------------
@@ -90,7 +108,7 @@ static void handle_fs_cb(uv_fs_t *req) {
 	value cb = (value)UV_REQ_DATA(req);
 	value res = caml_alloc(1, req->result < 0 ? 0 : 1);
 	if (req->result < 0)
-		Field(res, 0) = caml_copy_string(uv_strerror(req->result));
+		Field(res, 0) = req->result;
 	else
 		Field(res, 0) = Val_unit;
 	caml_callback(cb, res);
@@ -110,7 +128,7 @@ static value handle_fs_cb_sync(uv_fs_t *req) {
 		value cb = (value)UV_REQ_DATA(req); \
 		value res = caml_alloc(1, req->result < 0 ? 0 : 1); \
 		if (req->result < 0) \
-			Field(res, 0) = caml_copy_string(uv_strerror(req->result)); \
+			Field(res, 0) = req->result; \
 		else { \
 			value value2; \
 			do setup while (0); \
@@ -131,7 +149,7 @@ static value handle_fs_cb_sync(uv_fs_t *req) {
 
 UV_FS_HANDLER(handle_fs_cb_bytes, value2 = caml_copy_string((const char *)req->ptr););
 UV_FS_HANDLER(handle_fs_cb_path, value2 = caml_copy_string((const char *)req->path););
-UV_FS_HANDLER(handle_fs_cb_int, value2 = (value)req->result;);
+UV_FS_HANDLER(handle_fs_cb_int, value2 = Val_int(req->result););
 UV_FS_HANDLER(handle_fs_cb_file, value2 = (value)req->result;);
 UV_FS_HANDLER(handle_fs_cb_stat, {
 		value2 = caml_alloc(21, 0);
@@ -163,7 +181,7 @@ UV_FS_HANDLER(handle_fs_cb_scandir, {
 		while (uv_fs_scandir_next(req, &ent) != UV_EOF) {
 			value dirent = caml_alloc(2, 0);
 			Store_field(dirent, 0, caml_copy_string(ent.name));
-			Store_field(dirent, 1, ent.type);
+			Store_field(dirent, 1, Val_int(ent.type));
 			value node = caml_alloc(2, 0);
 			Store_field(node, 0, dirent); // car
 			Store_field(node, 1, value2); // cdr
@@ -178,7 +196,7 @@ UV_FS_HANDLER(handle_fs_cb_scandir, {
 		UV_REQ_DATA(req) = (void *)cb; \
 		caml_register_global_root(UV_REQ_DATA_A(req)); \
 		UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), handler), free((uv_fs_t *)req)); \
-		CAMLreturn(Val_unit); \
+		UV_SUCCESS_UNIT; \
 	} \
 	CAMLprim value w_ ## name ## _sync(value loop, value arg1) { \
 		CAMLparam2(loop, arg1); \
@@ -189,7 +207,7 @@ UV_FS_HANDLER(handle_fs_cb_scandir, {
 		value ret = handler ## _sync(req); \
 		uv_fs_req_cleanup(req); \
 		free(req); \
-		CAMLreturn(ret); \
+		UV_SUCCESS(ret); \
 	}
 
 #define FS_WRAP2(name, arg1conv, arg2conv, handler) \
@@ -199,7 +217,7 @@ UV_FS_HANDLER(handle_fs_cb_scandir, {
 		UV_REQ_DATA(req) = (void *)cb; \
 		caml_register_global_root(UV_REQ_DATA_A(req)); \
 		UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), handler), free((uv_fs_t *)req)); \
-		CAMLreturn(Val_unit); \
+		UV_SUCCESS_UNIT; \
 	} \
 	CAMLprim value w_ ## name ## _sync(value loop, value arg1, value arg2) { \
 		CAMLparam3(loop, arg1, arg2); \
@@ -210,7 +228,7 @@ UV_FS_HANDLER(handle_fs_cb_scandir, {
 		value ret = handler ## _sync(req); \
 		uv_fs_req_cleanup(req); \
 		free(req); \
-		CAMLreturn(ret); \
+		UV_SUCCESS(ret); \
 	}
 
 #define FS_WRAP3(name, arg1conv, arg2conv, arg3conv, handler) \
@@ -220,7 +238,7 @@ UV_FS_HANDLER(handle_fs_cb_scandir, {
 		UV_REQ_DATA(req) = (void *)cb; \
 		caml_register_global_root(UV_REQ_DATA_A(req)); \
 		UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), arg3conv(arg3), handler), free((uv_fs_t *)req)); \
-		CAMLreturn(Val_unit); \
+		UV_SUCCESS_UNIT; \
 	} \
 	CAMLprim value w_ ## name ## _sync(value loop, value arg1, value arg2, value arg3) { \
 		CAMLparam4(loop, arg1, arg2, arg3); \
@@ -231,15 +249,35 @@ UV_FS_HANDLER(handle_fs_cb_scandir, {
 		value ret = handler ## _sync(req); \
 		uv_fs_req_cleanup(req); \
 		free(req); \
-		CAMLreturn(ret); \
+		UV_SUCCESS(ret); \
 	}
 
-/**
-	FIXME:
-		w_fs_read, w_fs_write, w_fs_read_sync, and w_fs_write_sync
-		have a signature different from libuv due to no struct passing support in
-		hashlink; currently only a single uv_buf_t can be passed at a time.
-**/
+CAMLprim value w_fs_read(value loop, value file, value buffer, value offset, value length, value position, value cb) {
+	CAMLparam5(loop, file, buffer, offset, length);
+	CAMLxparam2(position, cb);
+	UV_ALLOC_CHECK(req, uv_fs_t);
+	UV_REQ_DATA(req) = (void *)cb;
+	caml_register_global_root(UV_REQ_DATA_A(req));
+	uv_buf_t buf = uv_buf_init(&Byte(buffer, Int_val(offset)), Int_val(length));
+	UV_ERROR_CHECK_C(uv_fs_read((uv_loop_t *)loop, (uv_fs_t *)req, (uv_file)file, &buf, 1, Val_int(position), handle_fs_cb_int), free(req));
+	UV_SUCCESS_UNIT;
+}
+CAMLprim value w_fs_read_bytecode(value *argv, int argc) {
+	return w_fs_read(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
+}
+
+CAMLprim value w_fs_read_sync(value loop, value file, value buffer, value offset, value length, value position) {
+	CAMLparam5(loop, file, buffer, offset, length);
+	CAMLxparam1(position);
+	UV_ALLOC_CHECK(req, uv_fs_t);
+	uv_buf_t buf = uv_buf_init(&Byte(buffer, Int_val(offset)), Int_val(length));
+	uv_buf_t bufs[1] = {buf};
+	UV_ERROR_CHECK_C(uv_fs_read((uv_loop_t *)loop, (uv_fs_t *)req, (uv_file)file, bufs, 1, Int_val(position), NULL), free(req));
+	UV_SUCCESS(handle_fs_cb_int_sync(req));
+}
+CAMLprim value w_fs_read_sync_bytecode(value *argv, int argc) {
+	return w_fs_read_sync(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+}
 	/*
 HL_PRIM void HL_NAME(w_fs_read)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset, vclosure *cb) {
 	UV_ALLOC_CHECK(req, uv_fs_t);
@@ -266,8 +304,7 @@ HL_PRIM int HL_NAME(w_fs_write_sync)(uv_loop_t *loop, uv_file file, const uv_buf
 	UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, buf, 1, offset, NULL), free(req));
 	return handle_fs_cb_int_sync(req);
 }
-
-*/
+	*/
 FS_WRAP1(fs_close, (uv_file), handle_fs_cb);
 FS_WRAP3(fs_open, String_val, Int_val, Int_val, handle_fs_cb_file);
 FS_WRAP1(fs_unlink, String_val, handle_fs_cb);

+ 6 - 4
src/macro/eval/evalDecode.ml

@@ -80,16 +80,18 @@ let decode_bool v = match v with
 	| VFalse -> false
 	| _ -> unexpected_value v "bool"
 
-let decode_func v = match v with
-	| VFunction (f, _) -> f
-	| _ -> unexpected_value v "function"
-
 let default_int v vd = match v with
 	| VNull -> vd
 	| VInt32 i -> Int32.to_int i
 	| VFloat f -> int_of_float f
 	| _ -> unexpected_value v "int"
 
+let default_bool v vd = match v with
+	| VNull -> vd
+	| VTrue -> true
+	| VFalse -> false
+	| _ -> unexpected_value v "bool"
+
 let decode_unsafe v = match v with
 	| VInstance {ikind = IRef o} -> o
 	| _ -> unexpected_value v "unsafe"

+ 5 - 0
src/macro/eval/evalHash.ml

@@ -40,6 +40,8 @@ let key_get = hash "get"
 let key_pos = hash "pos"
 let key_len = hash "len"
 let key_message = hash "message"
+let key_bytesRead = hash "bytesRead"
+let key_buffer = hash "buffer"
 let key_Array = hash "Array"
 let key_eval_Vector = hash "eval.Vector"
 let key_String = hash "String"
@@ -131,4 +133,7 @@ let key_sys_net_Lock = hash "sys.thread.Lock"
 let key_sys_net_Tls = hash "sys.thread.Tls"
 let key_sys_net_Deque = hash "sys.thread.Deque"
 let key_eval_Uv = hash "eval.Uv"
+let key_eval_uv_DirectoryEntry = hash "eval.uv.DirectoryEntry"
 let key_eval_uv_Loop = hash "eval.uv.Loop"
+let key_eval_uv_Stat = hash "eval.uv.Stat"
+let key_nusys_io_File = hash "nusys.io.File"

+ 367 - 15
src/macro/eval/evalStdLib.ml

@@ -3072,60 +3072,359 @@ module StdUv = struct
 	let loop_ref = ref None
 	let loop () = Option.get !loop_ref
 
+	(* Wrap a libuv error code *)
+	let wrap_error errno =
+		let key = path_hash (["haxe"],"Error") in
+		let ctx = get_ctx() in
+		let fnew = get_instance_constructor ctx key null_pos in
+		let proto = get_instance_prototype ctx key null_pos in
+		let v = lazy (match Lazy.force fnew with VFunction (f,_) -> f | _ -> exc_string "failure to throw error") in
+		let f = Lazy.force v in
+		let vthis = create_instance_direct proto INormal in
+		let vl = [vint errno] in
+		ignore(f (vthis :: vl));
+		vthis
+
+	let wrap_sync = function
+		| Uv.UvError err -> exc (wrap_error err)
+		| Uv.UvSuccess v -> v
+
 	(* Wrap a Haxe callback which will take no result *)
 	let wrap_cb_unit cb = (fun res ->
 		ignore (match res with
-			| Uv.CbError err -> call_value cb [encode_string err; vnull]
-			| Uv.CbSuccess () -> call_value cb [vnull; vnull])
+			| Uv.UvError err -> call_value cb [wrap_error err; vnull]
+			| Uv.UvSuccess () -> call_value cb [vnull; vnull])
 	)
 
 	(* Wrap a Haxe callback which will take a result, as encoded by `enc` *)
 	(*let wrap_cb cb enc = (fun res ->
-		match res with
-			| Uv.CbError err -> call_value cb [encode_string err; vnull]
-			| Uv.CbSuccess val -> call_value cb [vnull; enc val]
+		ignore (match res with
+			| Uv.UvError err -> call_value cb [encode_string err; vnull]
+			| Uv.UvSuccess val -> call_value cb [vnull; enc val])
 	)*)
 
+	module DirectoryEntry = struct
+		let this vthis = match vthis with
+			| VInstance {ikind = IUv (UvDirent e)} -> e
+			| v -> unexpected_value v "UVDirent"
+		let get_name = vifun0 (fun vthis ->
+			let this = this vthis in
+			encode_string (fst this)
+		)
+		let get_type = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint (snd this)
+		)
+	end
+
 	module Loop = struct
 		let this vthis = match vthis with
 			| VInstance {ikind = IUv (UvLoop l)} -> l
 			| v -> unexpected_value v "UVLoop"
 	end
 
+	module Stat = struct
+		let this vthis = match vthis with
+			| VInstance {ikind = IUv (UvStat l)} -> l
+			| v -> unexpected_value v "UVStat"
+		let get_dev = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.dev
+		)
+		let get_mode = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.kind
+		)
+		let get_nlink = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.nlink
+		)
+		let get_uid = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.uid
+		)
+		let get_gid = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.gid
+		)
+		let get_rdev = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.rdev
+		)
+		let get_ino = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.ino
+		)
+		let get_size = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint (Int64.to_int this.size)
+		)
+		let get_blksize = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.blksize
+		)
+		let get_blocks = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.blocks
+		)
+		let get_flags = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.flags
+		)
+		let get_gen = vifun0 (fun vthis ->
+			let this = this vthis in
+			vint this.gen
+		)
+		let isBlockDevice = vifun0 (fun vthis ->
+			let this = this vthis in
+			vbool ((this.kind land Uv.s_IFMT) = Uv.s_IFBLK)
+		)
+		let isCharacterDevice = vifun0 (fun vthis ->
+			let this = this vthis in
+			vbool ((this.kind land Uv.s_IFMT) = Uv.s_IFCHR)
+		)
+		let isDirectory = vifun0 (fun vthis ->
+			let this = this vthis in
+			vbool ((this.kind land Uv.s_IFMT) = Uv.s_IFDIR)
+		)
+		let isFIFO = vifun0 (fun vthis ->
+			let this = this vthis in
+			vbool ((this.kind land Uv.s_IFMT) = Uv.s_IFIFO)
+		)
+		let isFile = vifun0 (fun vthis ->
+			let this = this vthis in
+			vbool ((this.kind land Uv.s_IFMT) = Uv.s_IFREG)
+		)
+		let isSocket = vifun0 (fun vthis ->
+			let this = this vthis in
+			vbool ((this.kind land Uv.s_IFMT) = Uv.s_IFSOCK)
+		)
+		let isSymbolicLink = vifun0 (fun vthis ->
+			let this = this vthis in
+			vbool ((this.kind land Uv.s_IFMT) = Uv.s_IFLNK)
+		)
+	end
+
+	module File = struct
+		let this vthis = match vthis with
+			| VInstance {ikind = IUv (UvFile f)} -> f
+			| v -> unexpected_value v "UVFile"
+		let chmod = vifun1 (fun vthis mode ->
+			let this = this vthis in
+			let mode = decode_int mode in
+			wrap_sync (Uv.fs_fchmod_sync (loop ()) this mode);
+			vnull
+		)
+		let chown = vifun2 (fun vthis uid gid ->
+			let this = this vthis in
+			let uid = decode_int uid in
+			let gid = decode_int gid in
+			wrap_sync (Uv.fs_fchown_sync (loop ()) this uid gid);
+			vnull
+		)
+		let close = vifun0 (fun vthis ->
+			let this = this vthis in
+			wrap_sync (Uv.fs_close_sync (loop ()) this);
+			vnull
+		)
+		let datasync = vifun0 (fun vthis ->
+			let this = this vthis in
+			wrap_sync (Uv.fs_fdatasync_sync (loop ()) this);
+			vnull
+		)
+		let read = vifun4 (fun vthis buffer_i offset length position ->
+			let this = this vthis in
+			let buffer = decode_bytes buffer_i in
+			let offset = decode_int offset in
+			let length = decode_int length in
+			let position = decode_int position in
+			if length <= 0 || offset < 0 || length + offset > (Bytes.length buffer) then
+				exc_string "invalid call";
+			let bytesRead = wrap_sync (Uv.fs_read_sync (loop ()) this buffer offset length position) in
+			encode_obj [key_bytesRead,vint bytesRead;key_buffer,buffer_i]
+		)
+		let stat = vifun0 (fun vthis ->
+			let this = this vthis in
+			let stat = wrap_sync (Uv.fs_fstat_sync (loop ()) this) in
+			encode_instance key_eval_uv_Stat ~kind:(IUv (UvStat stat))
+		)
+		let sync = vifun0 (fun vthis ->
+			let this = this vthis in
+			wrap_sync (Uv.fs_fsync_sync (loop ()) this);
+			vnull
+		)
+		let truncate = vifun1 (fun vthis len ->
+			let this = this vthis in
+			let len = decode_int len in
+			wrap_sync (Uv.fs_ftruncate_sync (loop ()) this (Int64.of_int len));
+			vnull
+		)
+		let utimes_native = vifun2 (fun vthis atime mtime ->
+			let this = this vthis in
+			let atime = decode_float atime in
+			let mtime = decode_float mtime in
+			wrap_sync (Uv.fs_futime_sync (loop ()) this atime mtime);
+			vnull
+		)
+	end
+
 	module FileSystem = struct
 		let access = vfun2 (fun path mode ->
+			let path = decode_string path in
+			let mode = default_int mode 0 in
+			wrap_sync (Uv.fs_access_sync (loop ()) path mode);
+			vnull
+		)
+		let chmod = vfun3 (fun path mode followSymLinks ->
 			let path = decode_string path in
 			let mode = decode_int mode in
-			Uv.fs_access_sync (loop ()) path 0;
+			let followSymLinks = decode_bool followSymLinks in
+			(if followSymLinks then
+				wrap_sync (Uv.fs_chmod_sync (loop ()) path mode)
+			else
+				exc_string "not implemented");
+			vnull
+		)
+		let chown = vfun4 (fun path uid gid followSymLinks ->
+			let path = decode_string path in
+			let uid = decode_int uid in
+			let gid = decode_int gid in
+			let followSymLinks = decode_bool followSymLinks in
+			(if followSymLinks then
+				wrap_sync (Uv.fs_chown_sync (loop ()) path uid gid)
+			else
+				exc_string "not implemented");
 			vnull
 		)
 		let exists = vfun1 (fun path ->
 			let path = decode_string path in
 			try
-				Uv.fs_access_sync (loop ()) path 0;
+				wrap_sync (Uv.fs_access_sync (loop ()) path 0);
 				vtrue
 			with _ ->
 				vfalse
 		)
+		let link = vfun2 (fun existingPath newPath ->
+			let existingPath = decode_string existingPath in
+			let newPath = decode_string newPath in
+			wrap_sync (Uv.fs_link_sync (loop ()) existingPath newPath);
+			vnull
+		)
+		let mkdir_native = vfun2 (fun path mode ->
+			let path = decode_string path in
+			let mode = decode_int mode in
+			wrap_sync (Uv.fs_mkdir_sync (loop ()) path mode);
+			vnull
+		)
+		let mkdtemp = vfun1 (fun prefix ->
+			let prefix = decode_string prefix in
+			let res = wrap_sync (Uv.fs_mkdtemp_sync (loop ()) prefix) in
+			encode_string res
+		)
+		let open_ = vfun4 (fun path flags mode binary ->
+			let path = decode_string path in
+			let flags = default_int flags 0 in
+			let mode = default_int mode 0o666 in
+			(*let binary = default_bool binary true in*)
+			let handle = wrap_sync (Uv.fs_open_sync (loop ()) path 2 mode) in
+			encode_instance key_nusys_io_File ~kind:(IUv (UvFile handle))
+		)
+		let readdirTypes = vfun1 (fun path ->
+			let path = decode_string path in
+			let entries = wrap_sync (Uv.fs_scandir_sync (loop ()) path 0) in
+			encode_array (List.map (fun e -> encode_instance key_eval_uv_DirectoryEntry ~kind:(IUv (UvDirent e))) entries)
+		)
+		let readlink = vfun1 (fun path ->
+			let path = decode_string path in
+			let res = wrap_sync (Uv.fs_readlink_sync (loop ()) path) in
+			encode_string res
+		)
+		let realpath = vfun1 (fun path ->
+			let path = decode_string path in
+			let res = wrap_sync (Uv.fs_realpath_sync (loop ()) path) in
+			encode_string res
+		)
+		let rename = vfun2 (fun oldPath newPath ->
+			let oldPath = decode_string oldPath in
+			let newPath = decode_string newPath in
+			wrap_sync (Uv.fs_rename_sync (loop ()) oldPath newPath);
+			vnull
+		)
+		let rmdir = vfun1 (fun path ->
+			let path = decode_string path in
+			wrap_sync (Uv.fs_rmdir_sync (loop ()) path);
+			vnull
+		)
+		let stat = vfun2 (fun path followSymLinks ->
+			let path = decode_string path in
+			let followSymLinks = default_bool followSymLinks true in
+			let stat = wrap_sync (if followSymLinks then
+				Uv.fs_stat_sync (loop ()) path
+			else
+				Uv.fs_lstat_sync (loop ()) path) in
+			encode_instance key_eval_uv_Stat ~kind:(IUv (UvStat stat))
+		)
+		let symlink = vfun3 (fun target newPath tp ->
+			let target = decode_string target in
+			let newPath = decode_string newPath in
+			let tp = decode_int tp in
+			wrap_sync (Uv.fs_symlink_sync (loop ()) target newPath tp);
+			vnull
+		)
+		let unlink = vfun1 (fun path ->
+			let path = decode_string path in
+			wrap_sync (Uv.fs_unlink_sync (loop ()) path);
+			vnull
+		)
+		let utimes_native = vfun3 (fun path atime mtime ->
+			let path = decode_string path in
+			let atime = decode_float atime in
+			let mtime = decode_float mtime in
+			wrap_sync (Uv.fs_utime_sync (loop ()) path atime mtime);
+			vnull
+		)
 	end
 
 	module AsyncFileSystem = struct
 		let access = vfun3 (fun path mode cb ->
 			let path = decode_string path in
-			(*let mode = decode_int mode in*)
-			Uv.fs_access (loop ()) path 0 (wrap_cb_unit cb);
+			let mode = default_int mode 0 in
+			(try Uv.fs_access (loop ()) path mode (wrap_cb_unit cb)
+				with Failure err -> exc_string err);
+			vnull
+		)
+		let exists = vfun2 (fun path cb ->
+			let path = decode_string path in
+			(try Uv.fs_access (loop ()) path 0 (fun res ->
+				ignore (match res with
+					| Uv.UvError err -> call_value cb [vnull; vfalse]
+					| Uv.UvSuccess () -> call_value cb [vnull; vtrue])
+				)
+				with Failure err -> exc_string err);
+			vnull
+		)
+		let readdirTypes = vfun2 (fun path cb ->
+			let path = decode_string path in
+			(try Uv.fs_scandir (loop ()) path 0 (fun res ->
+				ignore (match res with
+					| Uv.UvError err -> call_value cb [vnull; vfalse]
+					| Uv.UvSuccess entries ->
+						let entries = encode_array (List.map (fun e -> encode_instance key_eval_uv_DirectoryEntry ~kind:(IUv (UvDirent e))) entries) in
+						call_value cb [vnull; entries])
+				)
+				with Failure err -> exc_string err);
 			vnull
 		)
 	end
 
 	let init = vfun0 (fun () ->
-		loop_ref := Some (Uv.loop_init ());
+		loop_ref := Some (wrap_sync (Uv.loop_init ()));
 		(*encode_instance key_eval_uv_Loop ~kind:(IUv (UvLoop (Uv.loop_init ())))*)
 		vnull
 	)
 
 	let run = vfun0 (fun () ->
-		Uv.run (loop ()) 0;
+		ignore (wrap_sync (Uv.run (loop ()) 0));
 		vnull
 	)
 end
@@ -3730,12 +4029,65 @@ let init_standard_library builtins =
 	init_fields builtins (["eval";"uv"],"File") [] [];
 	init_fields builtins (["eval"],"Uv") [
 		"init",StdUv.init;
-		"run",StdUv.run
+		"run",StdUv.run;
 	] [];
 	init_fields builtins (["nusys"],"FileSystem") [
 		"access",StdUv.FileSystem.access;
-		"exists",StdUv.FileSystem.exists
+		"chmod",StdUv.FileSystem.chmod;
+		"chown",StdUv.FileSystem.chown;
+		"exists",StdUv.FileSystem.exists;
+		"link",StdUv.FileSystem.link;
+		"mkdir_native",StdUv.FileSystem.mkdir_native;
+		"mkdtemp",StdUv.FileSystem.mkdtemp;
+		"open",StdUv.FileSystem.open_;
+		"readdirTypes",StdUv.FileSystem.readdirTypes;
+		"readlink",StdUv.FileSystem.readlink;
+		"realpath",StdUv.FileSystem.realpath;
+		"rename",StdUv.FileSystem.rename;
+		"rmdir",StdUv.FileSystem.rmdir;
+		"stat",StdUv.FileSystem.stat;
+		"symlink",StdUv.FileSystem.symlink;
+		"unlink",StdUv.FileSystem.unlink;
+		"utimes_native",StdUv.FileSystem.utimes_native;
 	] [];
 	init_fields builtins (["nusys";"async"],"FileSystem") [
-		"access",StdUv.AsyncFileSystem.access
-	] []
+		"access",StdUv.AsyncFileSystem.access;
+		"exists",StdUv.AsyncFileSystem.exists;
+		"readdirTypes",StdUv.AsyncFileSystem.readdirTypes;
+	] [];
+	init_fields builtins (["nusys";"io"],"File") [] [
+		"chmod",StdUv.File.chmod;
+		"chown",StdUv.File.chown;
+		"close",StdUv.File.close;
+		"datasync",StdUv.File.datasync;
+		"read",StdUv.File.read;
+		"stat",StdUv.File.stat;
+		"sync",StdUv.File.sync;
+		"truncate",StdUv.File.truncate;
+		"utimes_native",StdUv.File.utimes_native;
+	];
+	init_fields builtins (["eval";"uv"],"DirectoryEntry") [] [
+		"get_name",StdUv.DirectoryEntry.get_name;
+		"get_type",StdUv.DirectoryEntry.get_type;
+	];
+	init_fields builtins (["eval";"uv"],"Stat") [] [
+		"get_dev",StdUv.Stat.get_dev;
+		"get_mode",StdUv.Stat.get_mode;
+		"get_nlink",StdUv.Stat.get_nlink;
+		"get_uid",StdUv.Stat.get_uid;
+		"get_gid",StdUv.Stat.get_gid;
+		"get_rdev",StdUv.Stat.get_rdev;
+		"get_ino",StdUv.Stat.get_ino;
+		"get_size",StdUv.Stat.get_size;
+		"get_blksize",StdUv.Stat.get_blksize;
+		"get_blocks",StdUv.Stat.get_blocks;
+		"get_flags",StdUv.Stat.get_flags;
+		"get_gen",StdUv.Stat.get_gen;
+		"isBlockDevice",StdUv.Stat.isBlockDevice;
+		"isCharacterDevice",StdUv.Stat.isCharacterDevice;
+		"isDirectory",StdUv.Stat.isDirectory;
+		"isFIFO",StdUv.Stat.isFIFO;
+		"isFile",StdUv.Stat.isFile;
+		"isSocket",StdUv.Stat.isSocket;
+		"isSymbolicLink",StdUv.Stat.isSymbolicLink;
+	];

+ 1 - 0
src/macro/eval/evalValue.ml

@@ -97,6 +97,7 @@ type vuv_value =
 	| UvLoop of Uv.t_loop
 	| UvFile of Uv.t_file
 	| UvStat of Uv.t_stat
+	| UvDirent of (string * int)
 
 type value =
 	| VNull

+ 2 - 0
std/eval/_std/Sys.hx

@@ -92,5 +92,7 @@ class Sys {
 		// it into the interpreter, and then stderr() et. al. don't work.
 		var _ = (null : sys.io.FileOutput);
 		var _ = (null : sys.io.FileInput);
+
+		var _ = (null : haxe.Error);
 	}
 }