xbintsc 0.3.12 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +21 -3
  2. package/README.zh-CN.md +18 -3
  3. package/dist/src/codegen/generator/calls/access.js +13 -0
  4. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  5. package/dist/src/codegen/generator/calls/invocation.js +8 -2
  6. package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
  7. package/dist/src/codegen/generator/context.d.ts +23 -0
  8. package/dist/src/codegen/generator/context.js +91 -17
  9. package/dist/src/codegen/generator/context.js.map +1 -1
  10. package/dist/src/codegen/generator/expressions/primary.js +5 -0
  11. package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
  12. package/dist/src/driver/compiler.d.ts +7 -0
  13. package/dist/src/driver/compiler.js +41 -5
  14. package/dist/src/driver/compiler.js.map +1 -1
  15. package/dist/src/driver/modules.d.ts +1 -1
  16. package/dist/src/driver/modules.js +235 -25
  17. package/dist/src/driver/modules.js.map +1 -1
  18. package/dist/src/extensions/node/fs/fs-ops.d.ts +5 -2
  19. package/dist/src/extensions/node/fs/fs-ops.js +45 -6
  20. package/dist/src/extensions/node/fs/fs-ops.js.map +1 -1
  21. package/dist/src/extensions/node/fs/index.d.ts +6 -2
  22. package/dist/src/extensions/node/fs/index.js +22 -3
  23. package/dist/src/extensions/node/fs/index.js.map +1 -1
  24. package/dist/src/extensions/node/fs-promises/index.d.ts +4 -3
  25. package/dist/src/extensions/node/fs-promises/index.js +31 -3
  26. package/dist/src/extensions/node/fs-promises/index.js.map +1 -1
  27. package/dist/tests/cli/main.test.js +17 -0
  28. package/dist/tests/cli/main.test.js.map +1 -1
  29. package/dist/tests/driver/compiler.test.js +93 -2
  30. package/dist/tests/driver/compiler.test.js.map +1 -1
  31. package/dist/tests/driver/modules.test.js +91 -4
  32. package/dist/tests/driver/modules.test.js.map +1 -1
  33. package/dist/tests/e2e/compile-node.test.js +240 -0
  34. package/dist/tests/e2e/compile-node.test.js.map +1 -1
  35. package/dist/tests/e2e/compile.test.js +12 -0
  36. package/dist/tests/e2e/compile.test.js.map +1 -1
  37. package/dist/tests/e2e/harness.js +11 -8
  38. package/dist/tests/e2e/harness.js.map +1 -1
  39. package/dist/tests/e2e/node-modules.test.js +1 -1
  40. package/dist/tests/e2e/node-modules.test.js.map +1 -1
  41. package/dist/tests/e2e/npm-modules.test.d.ts +9 -0
  42. package/dist/tests/e2e/npm-modules.test.js +55 -0
  43. package/dist/tests/e2e/npm-modules.test.js.map +1 -0
  44. package/dist/tests/e2e/runtime-coverage.test.d.ts +11 -0
  45. package/dist/tests/e2e/runtime-coverage.test.js +646 -0
  46. package/dist/tests/e2e/runtime-coverage.test.js.map +1 -0
  47. package/package.json +3 -2
  48. package/runtime/ext_node/buffer/parts/prototype.inc +7 -0
  49. package/runtime/ext_node/buffer/parts/search.inc +8 -4
  50. package/runtime/ext_node/child_process/child_process.c +5 -0
  51. package/runtime/ext_node/fs/constants.c +113 -0
  52. package/runtime/ext_node/fs/copy_ops.c +145 -0
  53. package/runtime/ext_node/fs/dir.c +101 -0
  54. package/runtime/ext_node/fs/fd_ops.c +405 -0
  55. package/runtime/ext_node/fs/fs_common.h +388 -5
  56. package/runtime/ext_node/fs/fs_ops.c +100 -139
  57. package/runtime/ext_node/fs/glob.c +232 -0
  58. package/runtime/ext_node/fs/link_ops.c +91 -0
  59. package/runtime/ext_node/fs/meta_ops.c +403 -0
  60. package/runtime/ext_node/fs/promises.c +275 -60
  61. package/runtime/ext_node/fs/read_file.c +8 -4
  62. package/runtime/ext_node/fs/watch.c +52 -0
  63. package/runtime/ext_node/fs/write_file.c +20 -11
  64. package/runtime/ext_node/stream/stream.c +19 -2
  65. package/runtime/rt.h +9 -0
  66. package/runtime/xt_io.c +21 -0
  67. package/scripts/coverage-runtime.ts +338 -0
  68. package/src/codegen/generator/calls/access.ts +15 -0
  69. package/src/codegen/generator/calls/invocation.ts +8 -2
  70. package/src/codegen/generator/context.ts +112 -21
  71. package/src/codegen/generator/expressions/primary.ts +5 -0
  72. package/src/driver/compiler.ts +42 -5
  73. package/src/driver/modules.ts +251 -26
  74. package/src/extensions/node/fs/fs-ops.ts +48 -6
  75. package/src/extensions/node/fs/index.ts +25 -3
  76. package/src/extensions/node/fs-promises/index.ts +33 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xbintsc",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "description": "xbintsc - a TypeScript binary compiler (TypeScript -> LLVM IR -> native binary)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -42,7 +42,8 @@
42
42
  "test": "vitest run",
43
43
  "test:watch": "vitest",
44
44
  "test:e2e": "vitest run tests/e2e",
45
- "coverage": "vitest run --coverage"
45
+ "coverage": "vitest run --coverage",
46
+ "coverage:runtime": "tsx scripts/coverage-runtime.ts"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@eslint/js": "^9.39.5",
@@ -52,3 +52,10 @@ unsigned char *xt_node_buffer_bytes(xt_value value, size_t *outLength) {
52
52
  *outLength = length;
53
53
  return bytes;
54
54
  }
55
+
56
+ /* Cross-module helpers used by the fs module to fill/read Buffer objects. */
57
+ uint32_t xt_node_buffer_length(xt_value value) { return xt_buffer_length(value); }
58
+
59
+ void xt_node_buffer_set(xt_value value, uint32_t index, unsigned char byte) {
60
+ xt_buffer_put(value, index, byte);
61
+ }
@@ -1,12 +1,14 @@
1
1
  /* -- search --------------------------------------------------------------- */
2
2
 
3
3
  static const unsigned char *xt_buffer_search_needle(xt_value value, const char *encoding, size_t *length,
4
- unsigned char *single) {
4
+ unsigned char *single, int *heapAllocated) {
5
5
  if (XT_IS_NUMBER(value)) {
6
6
  *single = (unsigned char)((int32_t)xt_to_number(value) & 0xff);
7
7
  *length = 1;
8
+ *heapAllocated = 0;
8
9
  return single;
9
10
  }
11
+ *heapAllocated = 1;
10
12
  if (xt_buffer_is(value)) {
11
13
  uint32_t n = xt_buffer_length(value);
12
14
  unsigned char *bytes = (unsigned char *)malloc(n ? n : 1);
@@ -28,13 +30,15 @@ static xt_value xt_buffer_method_index_of(xt_value thisValue, xt_value env, int3
28
30
  const char *encoding = argc > 2 ? xt_node_encoding(argv[2]) : NULL;
29
31
  size_t needleLength = 0;
30
32
  unsigned char single = 0;
31
- const unsigned char *needle = xt_buffer_search_needle(xt_arg_at(argc, argv, 0), encoding, &needleLength, &single);
33
+ int needleOnHeap = 0;
34
+ const unsigned char *needle =
35
+ xt_buffer_search_needle(xt_arg_at(argc, argv, 0), encoding, &needleLength, &single, &needleOnHeap);
32
36
  uint32_t length = xt_buffer_length(thisValue);
33
37
  int32_t start = argc > 1 ? (int32_t)xt_to_number(argv[1]) : (reverse ? (int32_t)length - 1 : 0);
34
38
  if (start < 0) start += (int32_t)length;
35
39
  if (start < 0) start = 0;
36
40
  if (needleLength == 0 || needleLength > length) {
37
- if (!xt_buffer_is(xt_arg_at(argc, argv, 0))) free((void *)needle);
41
+ if (needleOnHeap) free((void *)needle);
38
42
  return xt_number(-1);
39
43
  }
40
44
  int found = -1;
@@ -68,7 +72,7 @@ static xt_value xt_buffer_method_index_of(xt_value thisValue, xt_value env, int3
68
72
  }
69
73
  }
70
74
  }
71
- if (!xt_buffer_is(xt_arg_at(argc, argv, 0))) free((void *)needle);
75
+ if (needleOnHeap) free((void *)needle);
72
76
  return xt_number((double)found);
73
77
  }
74
78
 
@@ -112,6 +112,11 @@ xt_value xt_child_process_spawn_sync(int32_t argc, xt_value *argv) {
112
112
  return make_result(-1, "", "could not create temporary files");
113
113
  }
114
114
 
115
+ /* Flush anything the parent has already buffered on stdout/stderr before
116
+ * redirecting the descriptors; otherwise that pending output would be
117
+ * flushed into the child's capture file (and lost from the real stdout). */
118
+ fflush(stdout);
119
+ fflush(stderr);
115
120
  int saved_out = _dup(_fileno(stdout));
116
121
  int saved_err = _dup(_fileno(stderr));
117
122
  _dup2(_fileno(out_file), _fileno(stdout));
@@ -0,0 +1,113 @@
1
+ /*
2
+ * `fs.constants` for xbintsc.
3
+ *
4
+ * The numeric values mirror the host platform's `<fcntl.h>` / `<sys/stat.h>`
5
+ * (which is what Node reports on that platform). Constants a platform does not
6
+ * define are omitted rather than faked.
7
+ */
8
+
9
+ #include "../node_common.h"
10
+ #include "fs_common.h"
11
+
12
+ #include <sys/stat.h>
13
+
14
+ #if defined(_WIN32)
15
+ #include <fcntl.h>
16
+ #endif
17
+
18
+ #ifndef F_OK
19
+ #define F_OK 0
20
+ #endif
21
+ #ifndef R_OK
22
+ #define R_OK 4
23
+ #endif
24
+ #ifndef W_OK
25
+ #define W_OK 2
26
+ #endif
27
+ #ifndef X_OK
28
+ #define X_OK 1
29
+ #endif
30
+
31
+ #define XT_FS_CONST(name, value) xt_object_set(object, xt_string_from_cstr(name), xt_number((double)(value)))
32
+
33
+ xt_value xt_fs_constants(void) {
34
+ xt_value object = xt_object_new();
35
+
36
+ XT_FS_CONST("F_OK", F_OK);
37
+ XT_FS_CONST("R_OK", R_OK);
38
+ XT_FS_CONST("W_OK", W_OK);
39
+ XT_FS_CONST("X_OK", X_OK);
40
+
41
+ XT_FS_CONST("COPYFILE_EXCL", 1);
42
+ XT_FS_CONST("COPYFILE_FICLONE", 2);
43
+ XT_FS_CONST("COPYFILE_FICLONE_FORCE", 4);
44
+
45
+ #ifdef O_RDONLY
46
+ XT_FS_CONST("O_RDONLY", O_RDONLY);
47
+ #endif
48
+ #ifdef O_WRONLY
49
+ XT_FS_CONST("O_WRONLY", O_WRONLY);
50
+ #endif
51
+ #ifdef O_RDWR
52
+ XT_FS_CONST("O_RDWR", O_RDWR);
53
+ #endif
54
+ #ifdef O_CREAT
55
+ XT_FS_CONST("O_CREAT", O_CREAT);
56
+ #elif defined(_O_CREAT)
57
+ XT_FS_CONST("O_CREAT", _O_CREAT);
58
+ #endif
59
+ #ifdef O_EXCL
60
+ XT_FS_CONST("O_EXCL", O_EXCL);
61
+ #elif defined(_O_EXCL)
62
+ XT_FS_CONST("O_EXCL", _O_EXCL);
63
+ #endif
64
+ #ifdef O_TRUNC
65
+ XT_FS_CONST("O_TRUNC", O_TRUNC);
66
+ #elif defined(_O_TRUNC)
67
+ XT_FS_CONST("O_TRUNC", _O_TRUNC);
68
+ #endif
69
+ #ifdef O_APPEND
70
+ XT_FS_CONST("O_APPEND", O_APPEND);
71
+ #elif defined(_O_APPEND)
72
+ XT_FS_CONST("O_APPEND", _O_APPEND);
73
+ #endif
74
+ #ifdef O_NOCTTY
75
+ XT_FS_CONST("O_NOCTTY", O_NOCTTY);
76
+ #endif
77
+ #ifdef O_DIRECTORY
78
+ XT_FS_CONST("O_DIRECTORY", O_DIRECTORY);
79
+ #endif
80
+ #ifdef O_NOFOLLOW
81
+ XT_FS_CONST("O_NOFOLLOW", O_NOFOLLOW);
82
+ #endif
83
+ #ifdef O_SYNC
84
+ XT_FS_CONST("O_SYNC", O_SYNC);
85
+ #endif
86
+ #ifdef O_DSYNC
87
+ XT_FS_CONST("O_DSYNC", O_DSYNC);
88
+ #endif
89
+ #ifdef O_NONBLOCK
90
+ XT_FS_CONST("O_NONBLOCK", O_NONBLOCK);
91
+ #endif
92
+ #ifdef O_SYMLINK
93
+ XT_FS_CONST("O_SYMLINK", O_SYMLINK);
94
+ #endif
95
+
96
+ #if defined(_WIN32)
97
+ XT_FS_CONST("S_IFMT", _S_IFMT);
98
+ XT_FS_CONST("S_IFREG", _S_IFREG);
99
+ XT_FS_CONST("S_IFDIR", _S_IFDIR);
100
+ XT_FS_CONST("S_IFCHR", _S_IFCHR);
101
+ #else
102
+ XT_FS_CONST("S_IFMT", S_IFMT);
103
+ XT_FS_CONST("S_IFREG", S_IFREG);
104
+ XT_FS_CONST("S_IFDIR", S_IFDIR);
105
+ XT_FS_CONST("S_IFCHR", S_IFCHR);
106
+ XT_FS_CONST("S_IFBLK", S_IFBLK);
107
+ XT_FS_CONST("S_IFIFO", S_IFIFO);
108
+ XT_FS_CONST("S_IFLNK", S_IFLNK);
109
+ XT_FS_CONST("S_IFSOCK", S_IFSOCK);
110
+ #endif
111
+
112
+ return object;
113
+ }
@@ -0,0 +1,145 @@
1
+ /*
2
+ * Node.js `fs.cpSync` for xbintsc.
3
+ *
4
+ * Copies files, symbolic links and (with `recursive: true`) directories.
5
+ * Supported options: `recursive`, `force`, `errorOnExist`, `dereference`,
6
+ * `preserveTimestamps`. Other Node options are ignored (documented).
7
+ */
8
+
9
+ #include "../node_common.h"
10
+ #include "fs_common.h"
11
+
12
+ #if !defined(_WIN32)
13
+ #include <sys/time.h>
14
+ #include <unistd.h>
15
+ #endif
16
+
17
+ static int xt_fs_option_bool(xt_value options, const char *key, int fallback) {
18
+ if (!XT_IS_OBJECT(options)) return fallback;
19
+ xt_value value = xt_object_get_cstr(options, key);
20
+ if (XT_IS_UNDEFINED(value) || XT_IS_NULL(value)) return fallback;
21
+ return xt_truthy(value);
22
+ }
23
+
24
+ static void xt_fs_copy_file_bytes(const char *from, const char *to) {
25
+ FILE *source = fopen(from, "rb");
26
+ if (!source) {
27
+ xt_fs_error("open", from);
28
+ return;
29
+ }
30
+ FILE *destination = fopen(to, "wb");
31
+ if (!destination) {
32
+ fclose(source);
33
+ xt_fs_error("open", to);
34
+ return;
35
+ }
36
+ char buffer[8192];
37
+ size_t read;
38
+ while ((read = fread(buffer, 1, sizeof(buffer), source)) > 0) fwrite(buffer, 1, read, destination);
39
+ fclose(source);
40
+ fclose(destination);
41
+ }
42
+
43
+ static char *xt_fs_join(const char *dir, const char *name) {
44
+ size_t size = strlen(dir) + strlen(name) + 2;
45
+ char *path = (char *)malloc(size);
46
+ if (!path) return NULL;
47
+ snprintf(path, size, "%s/%s", dir, name);
48
+ return path;
49
+ }
50
+
51
+ static void xt_fs_copy_any(const char *src, const char *dest, xt_value options, int recursive) {
52
+ xt_fs_stat_t info;
53
+ if (xt_fs_lstat_fn(src, &info) != 0) {
54
+ xt_fs_raise_path("lstat", src);
55
+ return;
56
+ }
57
+ int force = xt_fs_option_bool(options, "force", 1);
58
+ int errorOnExist = xt_fs_option_bool(options, "errorOnExist", 0);
59
+ int dereference = xt_fs_option_bool(options, "dereference", 0);
60
+
61
+ if (S_ISDIR(info.st_mode)) {
62
+ if (!recursive) {
63
+ xt_fs_raise_errno(EISDIR, "cp", src);
64
+ return;
65
+ }
66
+ if (xt_fs_mkdir_mode(dest, (int)(info.st_mode & 0777)) != 0 && errno != EEXIST) {
67
+ xt_fs_raise_path("mkdir", dest);
68
+ return;
69
+ }
70
+ xt_fs_dir dir;
71
+ if (!xt_fs_dir_open(&dir, src)) {
72
+ xt_fs_error("open directory", src);
73
+ return;
74
+ }
75
+ while (xt_fs_dir_next(&dir)) {
76
+ const char *name = xt_fs_dir_name(&dir);
77
+ if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;
78
+ char *childSrc = xt_fs_join(src, name);
79
+ char *childDest = xt_fs_join(dest, name);
80
+ if (childSrc && childDest) xt_fs_copy_any(childSrc, childDest, options, recursive);
81
+ free(childSrc);
82
+ free(childDest);
83
+ }
84
+ xt_fs_dir_close(&dir);
85
+ return;
86
+ }
87
+
88
+ if (xt_fs_access(dest, F_OK) == 0) {
89
+ if (!force) {
90
+ if (errorOnExist) xt_fs_raise_errno(EEXIST, "cp", dest);
91
+ return;
92
+ }
93
+ }
94
+
95
+ #if !defined(_WIN32)
96
+ if (S_ISLNK(info.st_mode) && !dereference) {
97
+ size_t capacity = 256;
98
+ for (;;) {
99
+ char *target = (char *)malloc(capacity);
100
+ if (!target) return;
101
+ ssize_t length = readlink(src, target, capacity);
102
+ if (length < 0) {
103
+ free(target);
104
+ xt_fs_raise_path("readlink", src);
105
+ return;
106
+ }
107
+ if ((size_t)length < capacity) {
108
+ target[length] = '\0';
109
+ if (symlink(target, dest) != 0) xt_fs_raise_path("symlink", dest);
110
+ free(target);
111
+ return;
112
+ }
113
+ free(target);
114
+ capacity *= 2;
115
+ }
116
+ }
117
+ #endif
118
+
119
+ xt_fs_copy_file_bytes(src, dest);
120
+
121
+ if (xt_fs_option_bool(options, "preserveTimestamps", 0)) {
122
+ #if !defined(_WIN32)
123
+ struct timeval times[2];
124
+ times[0].tv_sec = info.st_atime;
125
+ times[0].tv_usec = 0;
126
+ times[1].tv_sec = info.st_mtime;
127
+ times[1].tv_usec = 0;
128
+ utimes(dest, times);
129
+ #endif
130
+ }
131
+ }
132
+
133
+ xt_value xt_node_cp(int32_t argc, xt_value *argv) {
134
+ if (argc < 2) return xt_undefined();
135
+ const char *src = xt_node_cstr(argv[0]);
136
+ const char *dest = xt_node_cstr(argv[1]);
137
+ if (!src || !dest) {
138
+ xt_fs_raise_errno(EINVAL, "cp", NULL);
139
+ return xt_undefined();
140
+ }
141
+ xt_value options = argc > 2 ? argv[2] : XT_UNDEFINED;
142
+ int recursive = xt_fs_option_bool(options, "recursive", 0);
143
+ xt_fs_copy_any(src, dest, options, recursive);
144
+ return xt_undefined();
145
+ }
@@ -0,0 +1,101 @@
1
+ /*
2
+ * `fs.opendirSync` / the `Dir` object for xbintsc.
3
+ *
4
+ * The runtime has no asynchronous thread pool, so `read`/`close` invoke their
5
+ * callbacks immediately (Node would defer them). `readSync`/`closeSync` are the
6
+ * fully synchronous equivalents. `Dir` is a plain object (there is no shared
7
+ * `Dir` prototype yet), so `dir instanceof Dir` is not supported.
8
+ */
9
+
10
+ #include "../node_common.h"
11
+ #include "fs_common.h"
12
+
13
+ static xt_fs_dir *xt_fs_dir_handle(xt_value thisValue) {
14
+ xt_value handle = xt_object_get_cstr(thisValue, "__xt_dir");
15
+ return (xt_fs_dir *)(uintptr_t)xt_to_number(handle);
16
+ }
17
+
18
+ static xt_value xt_fs_dir_read_entry(xt_value thisValue) {
19
+ xt_fs_dir *dir = xt_fs_dir_handle(thisValue);
20
+ if (!dir) return xt_null();
21
+ const char *path = xt_node_cstr(xt_object_get_cstr(thisValue, "path"));
22
+ while (xt_fs_dir_next(dir)) {
23
+ const char *name = xt_fs_dir_name(dir);
24
+ if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;
25
+ return xt_node_dirent_result(path ? path : "", name);
26
+ }
27
+ return xt_null();
28
+ }
29
+
30
+ static xt_value xt_fs_dir_read_sync(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
31
+ (void)env;
32
+ (void)argc;
33
+ (void)argv;
34
+ return xt_fs_dir_read_entry(thisValue);
35
+ }
36
+
37
+ static xt_value xt_fs_dir_close_sync(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
38
+ (void)env;
39
+ (void)argc;
40
+ (void)argv;
41
+ xt_fs_dir *dir = xt_fs_dir_handle(thisValue);
42
+ if (dir) {
43
+ xt_fs_dir_close(dir);
44
+ free(dir);
45
+ xt_object_set(thisValue, xt_string_from_cstr("__xt_dir"), xt_number(0));
46
+ }
47
+ return xt_undefined();
48
+ }
49
+
50
+ static xt_value xt_fs_dir_read_async(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
51
+ (void)env;
52
+ xt_value callback = xt_arg(argc, argv, 0);
53
+ xt_value dirent = xt_fs_dir_read_entry(thisValue);
54
+ if (XT_IS_FUNCTION(callback)) {
55
+ xt_value args[2];
56
+ args[0] = xt_null();
57
+ args[1] = dirent;
58
+ xt_call_with_this(callback, xt_undefined(), 2, args);
59
+ }
60
+ return xt_undefined();
61
+ }
62
+
63
+ static xt_value xt_fs_dir_close_async(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
64
+ (void)env;
65
+ xt_value callback = xt_arg(argc, argv, 0);
66
+ xt_fs_dir_close_sync(thisValue, env, 0, NULL);
67
+ if (XT_IS_FUNCTION(callback)) {
68
+ xt_value args[1];
69
+ args[0] = xt_null();
70
+ xt_call_with_this(callback, xt_undefined(), 1, args);
71
+ }
72
+ return xt_undefined();
73
+ }
74
+
75
+ xt_value xt_node_opendir(int32_t argc, xt_value *argv) {
76
+ if (argc < 1) return xt_undefined();
77
+ const char *path = xt_node_cstr(argv[0]);
78
+ if (!path) {
79
+ xt_fs_raise_errno(EINVAL, "opendir", NULL);
80
+ return xt_undefined();
81
+ }
82
+ xt_fs_dir *dir = (xt_fs_dir *)malloc(sizeof(xt_fs_dir));
83
+ if (!dir) {
84
+ xt_fs_raise_errno(ENOMEM, "opendir", path);
85
+ return xt_undefined();
86
+ }
87
+ if (!xt_fs_dir_open(dir, path)) {
88
+ free(dir);
89
+ xt_fs_error("open directory", path);
90
+ return xt_undefined();
91
+ }
92
+
93
+ xt_value object = xt_object_new();
94
+ xt_node_set(object, "path", xt_string_from_cstr(path));
95
+ xt_node_set(object, "__xt_dir", xt_number((double)(uintptr_t)dir));
96
+ xt_node_define_method(object, "readSync", (void *)xt_fs_dir_read_sync);
97
+ xt_node_define_method(object, "closeSync", (void *)xt_fs_dir_close_sync);
98
+ xt_node_define_method(object, "read", (void *)xt_fs_dir_read_async);
99
+ xt_node_define_method(object, "close", (void *)xt_fs_dir_close_async);
100
+ return object;
101
+ }