@effekt-lang/effekt 0.3.0 → 0.5.0
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.
- package/README.md +6 -18
- package/bin/effekt +0 -0
- package/libraries/common/args.effekt +0 -27
- package/libraries/common/array.effekt +34 -63
- package/libraries/common/bench.effekt +40 -22
- package/libraries/common/buffer.effekt +8 -20
- package/libraries/common/bytes.effekt +5 -15
- package/libraries/common/dequeue.effekt +5 -5
- package/libraries/common/effekt.effekt +51 -92
- package/libraries/common/exception.effekt +0 -1
- package/libraries/common/io/console.effekt +30 -36
- package/libraries/common/io/error.effekt +131 -30
- package/libraries/common/io/filesystem.effekt +262 -0
- package/libraries/common/io/network.effekt +30 -54
- package/libraries/common/io/time.effekt +9 -12
- package/libraries/common/io.effekt +54 -124
- package/libraries/common/list.effekt +345 -327
- package/libraries/common/process.effekt +0 -1
- package/libraries/common/queue.effekt +1 -3
- package/libraries/common/ref.effekt +11 -24
- package/libraries/common/result.effekt +6 -14
- package/libraries/common/seq.effekt +28 -49
- package/libraries/common/string/tty.effekt +66 -0
- package/libraries/common/string.effekt +7 -49
- package/libraries/common/test.effekt +96 -34
- package/libraries/js/unsafe/cont.effekt +1 -1
- package/libraries/llvm/io.c +258 -378
- package/libraries/llvm/main.c +3 -0
- package/libraries/llvm/rts.ll +57 -38
- package/libraries/llvm/types.c +10 -1
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
- package/licenses/mit license - mit-license.html +21 -20
- package/licenses/the bsd license - bsd-license.html +20 -21
- package/licenses/the mit license - mit.html +22 -21
- package/package.json +1 -1
- package/libraries/chez/lift/effekt.ss +0 -118
- package/libraries/common/io/files.effekt +0 -282
- package/libraries/js/io.js +0 -143
- package/libraries/llvm/io.ll +0 -19
- package/libraries/ml/effekt.sml +0 -65
- package/libraries/ml/internal/mllist.effekt +0 -9
- package/libraries/ml/internal/mloption.effekt +0 -18
- package/libraries/ml/random.effekt +0 -85
- package/libraries/ml/text/regex.effekt +0 -102
package/libraries/llvm/io.c
CHANGED
|
@@ -27,159 +27,153 @@ void c_io_println_String(String text) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
//
|
|
31
|
-
//
|
|
30
|
+
// Lib UV Bindings
|
|
31
|
+
// ---------------
|
|
32
|
+
// Ideas behind the LLVM / libuv implementation.
|
|
33
|
+
//
|
|
34
|
+
// Share memory between Effekt-buffers and libuv buffers
|
|
35
|
+
// -----------------------------------------------------
|
|
36
|
+
// A libuv buffer is a {ptr, i64} where i64 is the capacity
|
|
37
|
+
// while our buffer (from buffer.c, which is ref-counted) is a %Pos with a
|
|
38
|
+
// pointer and a length. The data ptr is shared between the two such that
|
|
39
|
+
// libuv (and underlying mechanisms) can directly write into our buffer without
|
|
40
|
+
// copying. Since our buffer is ref-counted, this has the advantage that we
|
|
41
|
+
// do not need to manually memory manage the buffer.
|
|
42
|
+
//
|
|
43
|
+
//
|
|
44
|
+
// Stacks in Data-fields
|
|
45
|
+
// ------------------------
|
|
46
|
+
// In order to return back to Effekt in the callback, we store a pointer
|
|
47
|
+
// to the Effekt stack into the user-definable data-field (at address 0)
|
|
48
|
+
// in each request object.
|
|
49
|
+
//
|
|
50
|
+
//
|
|
51
|
+
// TODO
|
|
52
|
+
// - pooling of request objects (benchmark first!)
|
|
32
53
|
|
|
33
|
-
typedef enum { UNRESOLVED, RESOLVED, AWAITED } promise_state_t;
|
|
34
54
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
} Listeners;
|
|
55
|
+
void c_resume_int_fs(uv_fs_t* request) {
|
|
56
|
+
int64_t result = (int64_t)request->result;
|
|
57
|
+
Stack stack = (Stack)request->data;
|
|
39
58
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
void* eraser;
|
|
43
|
-
promise_state_t state;
|
|
44
|
-
// state of {
|
|
45
|
-
// case UNRESOLVED => NULL
|
|
46
|
-
// case RESOLVED => Pos (the result)
|
|
47
|
-
// case AWAITED => Nonempty list of listeners
|
|
48
|
-
// }
|
|
49
|
-
union {
|
|
50
|
-
struct Pos pos;
|
|
51
|
-
Listeners* listeners;
|
|
52
|
-
} payload;
|
|
53
|
-
} Promise;
|
|
59
|
+
uv_fs_req_cleanup(request);
|
|
60
|
+
free(request);
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
resume_Int(stack, result);
|
|
63
|
+
}
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return;
|
|
74
|
-
case
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
int modeFlags(struct Pos mode) {
|
|
66
|
+
switch (mode.tag) {
|
|
67
|
+
case 0: // ReadOnly()
|
|
68
|
+
return UV_FS_O_RDONLY;
|
|
69
|
+
case 1: // WriteOnly()
|
|
70
|
+
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC;
|
|
71
|
+
case 2: // AppendOnly()
|
|
72
|
+
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND;
|
|
73
|
+
case 3: // ReadWrite()
|
|
74
|
+
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC;
|
|
75
|
+
case 4: // ReadAppend()
|
|
76
|
+
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND;
|
|
77
|
+
case 5: // AppendExclusive()
|
|
78
|
+
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_EXCL;
|
|
79
|
+
case 6: // ReadAppendExclusive()
|
|
80
|
+
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_EXCL;
|
|
81
|
+
case 7: // AppendSync()
|
|
82
|
+
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_SYNC;
|
|
83
|
+
case 8: // ReadAppendSync()
|
|
84
|
+
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_SYNC;
|
|
85
|
+
case 9: // ReadSync()
|
|
86
|
+
return UV_FS_O_RDONLY | UV_FS_O_SYNC;
|
|
87
|
+
case 10: // ReadWriteSync()
|
|
88
|
+
return UV_FS_O_RDWR | UV_FS_O_SYNC;
|
|
89
|
+
case 11: // WriteExclusive()
|
|
90
|
+
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL;
|
|
91
|
+
case 12: // ReadWriteExclusive()
|
|
92
|
+
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL;
|
|
93
|
+
default:
|
|
94
|
+
// Invalid tag value
|
|
95
|
+
return -1;
|
|
77
96
|
}
|
|
78
97
|
}
|
|
79
98
|
|
|
80
|
-
void
|
|
81
|
-
Promise* p = (Promise*)promise.obj;
|
|
99
|
+
void c_fs_open(struct Pos path, struct Pos mode, Stack stack) {
|
|
82
100
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
p->payload.pos = value; // Store value in payload
|
|
87
|
-
break;
|
|
88
|
-
case RESOLVED:
|
|
89
|
-
fprintf(stderr, "ERROR: Promise already resolved\n");
|
|
90
|
-
exit(1);
|
|
91
|
-
case AWAITED: {
|
|
92
|
-
Listeners* current = p->payload.listeners;
|
|
93
|
-
p->state = RESOLVED;
|
|
94
|
-
p->payload.pos = value;
|
|
101
|
+
// Convert the Effekt String to a 0-terminated string
|
|
102
|
+
char* path_str = c_buffer_as_null_terminated_string(path);
|
|
103
|
+
erasePositive((struct Pos) path);
|
|
95
104
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
// Convert the Effekt String representing the opening mode to libuv flags
|
|
106
|
+
int flags = modeFlags(mode);
|
|
107
|
+
erasePositive((struct Pos) mode);
|
|
108
|
+
|
|
109
|
+
uv_fs_t* request = malloc(sizeof(uv_fs_t));
|
|
110
|
+
request->data = stack;
|
|
111
|
+
|
|
112
|
+
int result = uv_fs_open(uv_default_loop(), request, path_str, flags, 0666, c_resume_int_fs);
|
|
113
|
+
|
|
114
|
+
if (result < 0) {
|
|
115
|
+
uv_fs_req_cleanup(request);
|
|
116
|
+
free(request);
|
|
117
|
+
resume_Int(stack, result);
|
|
106
118
|
}
|
|
107
|
-
|
|
108
|
-
|
|
119
|
+
|
|
120
|
+
// We must free the string either way, since libuv copies it into the request
|
|
121
|
+
free(path_str);
|
|
122
|
+
|
|
123
|
+
return;
|
|
109
124
|
}
|
|
110
125
|
|
|
111
|
-
void
|
|
112
|
-
Promise* p = (Promise*)promise.obj;
|
|
126
|
+
void c_fs_read(Int fd, struct Pos buffer, Int offset, Stack stack) {
|
|
113
127
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// We traverse the listeners to attach this last .
|
|
130
|
-
// This has O(n) for EACH await -- reverse on resolve would be O(n) ONCE.
|
|
131
|
-
// But how many listeners will there be?
|
|
132
|
-
// If really necessary, we can store a second pointer that points to the last one...
|
|
133
|
-
Listeners* current = p->payload.listeners;
|
|
134
|
-
while (current->next != NULL) {
|
|
135
|
-
current = current->next;
|
|
136
|
-
}
|
|
137
|
-
current->next = new_node;
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
128
|
+
char* bytes = (char*)c_buffer_bytes(buffer); // libuv expects signed integers
|
|
129
|
+
uv_buf_t buf = uv_buf_init(bytes, c_buffer_length(buffer));
|
|
130
|
+
// erasePositive(buffer);
|
|
131
|
+
// TODO we should erase the buffer but abort if this was the last reference
|
|
132
|
+
|
|
133
|
+
uv_fs_t* request = malloc(sizeof(uv_fs_t));
|
|
134
|
+
request->data = stack;
|
|
135
|
+
|
|
136
|
+
int result = uv_fs_read(uv_default_loop(), request, fd, &buf, 1, offset, c_resume_int_fs);
|
|
137
|
+
|
|
138
|
+
if (result < 0) {
|
|
139
|
+
uv_fs_req_cleanup(request);
|
|
140
|
+
free(request);
|
|
141
|
+
resume_Int(stack, result);
|
|
140
142
|
}
|
|
141
|
-
erasePositive(promise);
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
void c_fs_write(Int fd, struct Pos buffer, Int offset, Stack stack) {
|
|
144
146
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
char* bytes = (char*)c_buffer_bytes(buffer); // libuv expects signed integers
|
|
148
|
+
uv_buf_t buf = uv_buf_init(bytes, c_buffer_length(buffer));
|
|
149
|
+
// erasePositive(buffer);
|
|
150
|
+
// TODO we should erase the buffer but abort if this was the last reference
|
|
147
151
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
promise->state = UNRESOLVED;
|
|
151
|
-
promise->payload.pos = Unit;
|
|
152
|
+
uv_fs_t* request = malloc(sizeof(uv_fs_t));
|
|
153
|
+
request->data = stack;
|
|
152
154
|
|
|
153
|
-
|
|
155
|
+
int result = uv_fs_write(uv_default_loop(), request, fd, &buf, 1, offset, c_resume_int_fs);
|
|
156
|
+
|
|
157
|
+
if (result < 0) {
|
|
158
|
+
uv_fs_req_cleanup(request);
|
|
159
|
+
free(request);
|
|
160
|
+
resume_Int(stack, result);
|
|
161
|
+
}
|
|
154
162
|
}
|
|
155
163
|
|
|
164
|
+
void c_fs_close(Int fd, Stack stack) {
|
|
156
165
|
|
|
166
|
+
uv_fs_t* request = malloc(sizeof(uv_fs_t));
|
|
167
|
+
request->data = stack;
|
|
157
168
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
// pointer and a length. The data ptr is shared between the two such that
|
|
167
|
-
// libuv (and underlying mechanisms) can directly write into our buffer without
|
|
168
|
-
// copying. Since our buffer is ref-counted, this has the advantage that we
|
|
169
|
-
// do not need to manually memory manage the buffer.
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
// Callbacks in Data-fields
|
|
173
|
-
// ------------------------
|
|
174
|
-
// In order to call Effekt-functions as a callback, we store a pointer
|
|
175
|
-
// to their closure into the user-definable data-field (at address 0)
|
|
176
|
-
// in each request object.
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
// TODO
|
|
180
|
-
// - Error reporting
|
|
181
|
-
// - pooling of request objects (benchmark first!)
|
|
182
|
-
// - always pass by-reference, not by-value? (to work around C ABI issues)
|
|
169
|
+
int result = uv_fs_close(uv_default_loop(), request, fd, c_resume_int_fs);
|
|
170
|
+
|
|
171
|
+
if (result < 0) {
|
|
172
|
+
uv_fs_req_cleanup(request);
|
|
173
|
+
free(request);
|
|
174
|
+
resume_Int(stack, result);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
183
177
|
|
|
184
178
|
|
|
185
179
|
/**
|
|
@@ -188,8 +182,8 @@ struct Pos c_promise_make() {
|
|
|
188
182
|
* Tries to use most common errno integer values, but introduces fresh values (> 200)
|
|
189
183
|
* for those without common errno values.
|
|
190
184
|
*/
|
|
191
|
-
|
|
192
|
-
switch (
|
|
185
|
+
Int c_error_number(Int errno) {
|
|
186
|
+
switch (errno) {
|
|
193
187
|
case UV_EPERM: return 1; // EPERM
|
|
194
188
|
case UV_ENOENT: return 2; // ENOENT
|
|
195
189
|
case UV_ESRCH: return 3; // ESRCH
|
|
@@ -277,289 +271,175 @@ int uv_error_to_errno(int uv_err) {
|
|
|
277
271
|
}
|
|
278
272
|
}
|
|
279
273
|
|
|
274
|
+
void c_resume_unit_timer(uv_timer_t* handle) {
|
|
275
|
+
Stack stack = handle->data;
|
|
280
276
|
|
|
281
|
-
// File Descriptors
|
|
282
|
-
// ----------------
|
|
283
|
-
// Extern type defs at the moment are always treated as %Pos.
|
|
284
|
-
// For this reason, we need to translate the 32bit integer into
|
|
285
|
-
// a %Pos in the following way:
|
|
286
|
-
//
|
|
287
|
-
// +----------------+-------+
|
|
288
|
-
// | filedescriptor | Obj |
|
|
289
|
-
// | 32bit -> 64bit | NULL |
|
|
290
|
-
// +----------------+-------+
|
|
291
|
-
struct Pos filedescriptor_to_pos(int32_t fd) {
|
|
292
|
-
return (struct Pos) { .tag = (int64_t) fd, .obj = NULL, };
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
int32_t pos_to_filedescriptor(struct Pos fd) {
|
|
296
|
-
return (int32_t) fd.tag;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
struct Pos c_filedescriptor_show(struct Pos fd) {
|
|
300
|
-
return c_buffer_show_Int(pos_to_filedescriptor(fd));
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Timers
|
|
304
|
-
// ------
|
|
305
|
-
|
|
306
|
-
void c_timer_handler(uv_timer_t* handle) {
|
|
307
|
-
// Load callback
|
|
308
|
-
struct Neg callback = *(struct Neg*)handle->data;
|
|
309
|
-
|
|
310
|
-
// Clean up
|
|
311
277
|
uv_timer_stop(handle);
|
|
312
|
-
|
|
313
|
-
free(handle);
|
|
278
|
+
uv_close((uv_handle_t*)handle, (uv_close_cb)free);
|
|
314
279
|
|
|
315
|
-
|
|
316
|
-
run(callback);
|
|
280
|
+
resume_Pos(stack, Unit);
|
|
317
281
|
}
|
|
318
282
|
|
|
319
|
-
void
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
uv_loop_t* loop = uv_default_loop();
|
|
323
|
-
|
|
324
|
-
// Allocate memory for the timer handle
|
|
325
|
-
uv_timer_t* timer = (uv_timer_t*)malloc(sizeof(uv_timer_t));
|
|
326
|
-
|
|
327
|
-
// // Initialize the timer handle
|
|
328
|
-
uv_timer_init(loop, timer);
|
|
329
|
-
|
|
330
|
-
// Allocate memory for the callback (of type Neg)
|
|
331
|
-
struct Neg* payload = (struct Neg*)malloc(sizeof(struct Neg));
|
|
332
|
-
payload->vtable = callback.vtable;
|
|
333
|
-
payload->obj = callback.obj;
|
|
334
|
-
|
|
335
|
-
// Store the Neg pointer in the timer's data field
|
|
336
|
-
timer->data = (void*) payload;
|
|
337
|
-
|
|
338
|
-
// Start the timer to call the callback after n ms
|
|
339
|
-
uv_timer_start(timer, c_timer_handler, n, 0);
|
|
340
|
-
}
|
|
283
|
+
void c_timer_start(Int millis, Stack stack) {
|
|
284
|
+
uv_timer_t* timer = malloc(sizeof(uv_timer_t));
|
|
285
|
+
timer->data = stack;
|
|
341
286
|
|
|
287
|
+
uv_timer_init(uv_default_loop(), timer);
|
|
342
288
|
|
|
343
|
-
|
|
344
|
-
// --------------
|
|
345
|
-
|
|
346
|
-
int modeToFlags(const char* flags) {
|
|
347
|
-
if (strcmp(flags, "r") == 0) {
|
|
348
|
-
return UV_FS_O_RDONLY;
|
|
349
|
-
} else if (strcmp(flags, "r+") == 0) {
|
|
350
|
-
return UV_FS_O_RDWR;
|
|
351
|
-
} else if (strcmp(flags, "rs") == 0) {
|
|
352
|
-
return UV_FS_O_RDONLY | UV_FS_O_SYNC;
|
|
353
|
-
} else if (strcmp(flags, "rs+") == 0) {
|
|
354
|
-
return UV_FS_O_RDWR | UV_FS_O_SYNC;
|
|
355
|
-
} else if (strcmp(flags, "w") == 0) {
|
|
356
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC;
|
|
357
|
-
} else if (strcmp(flags, "wx") == 0) {
|
|
358
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL;
|
|
359
|
-
} else if (strcmp(flags, "w+") == 0) {
|
|
360
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC;
|
|
361
|
-
} else if (strcmp(flags, "wx+") == 0) {
|
|
362
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL;
|
|
363
|
-
} else if (strcmp(flags, "a") == 0) {
|
|
364
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND;
|
|
365
|
-
} else if (strcmp(flags, "ax") == 0) {
|
|
366
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_EXCL;
|
|
367
|
-
} else if (strcmp(flags, "a+") == 0) {
|
|
368
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND;
|
|
369
|
-
} else if (strcmp(flags, "ax+") == 0) {
|
|
370
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_EXCL;
|
|
371
|
-
} else if (strcmp(flags, "as") == 0) {
|
|
372
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_SYNC;
|
|
373
|
-
} else if (strcmp(flags, "as+") == 0) {
|
|
374
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_SYNC;
|
|
375
|
-
} else {
|
|
376
|
-
// Invalid flags string
|
|
377
|
-
return -1;
|
|
378
|
-
}
|
|
289
|
+
uv_timer_start(timer, c_resume_unit_timer, millis, 0);
|
|
379
290
|
}
|
|
380
291
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
struct Neg on_failure;
|
|
384
|
-
} Callbacks;
|
|
385
|
-
|
|
386
|
-
void c_file_open_handler(uv_fs_t* req) {
|
|
387
|
-
// Extract the file descriptor from the uv_fs_t structure
|
|
388
|
-
int64_t fd = req->result;
|
|
389
|
-
|
|
390
|
-
// Load the callbacks
|
|
391
|
-
Callbacks* callbacks = (Callbacks*)req->data;
|
|
392
|
-
struct Neg success = callbacks->on_success;
|
|
393
|
-
struct Neg failure = callbacks->on_failure;
|
|
394
|
-
|
|
395
|
-
// Free request structure
|
|
396
|
-
uv_fs_req_cleanup(req);
|
|
397
|
-
free(req);
|
|
398
|
-
free(callbacks);
|
|
399
|
-
|
|
400
|
-
// Check if file descriptor is valid
|
|
401
|
-
if (fd >= 0) {
|
|
402
|
-
eraseNegative(failure);
|
|
403
|
-
run_Pos(success, filedescriptor_to_pos(fd));
|
|
404
|
-
} else {
|
|
405
|
-
eraseNegative(success);
|
|
406
|
-
run_i64(failure, uv_error_to_errno(fd));
|
|
407
|
-
}
|
|
292
|
+
void c_yield(Stack stack) {
|
|
293
|
+
c_timer_start(0, stack);
|
|
408
294
|
}
|
|
409
295
|
|
|
410
296
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
uv_fs_t* req = (uv_fs_t*)malloc(sizeof(uv_fs_t));
|
|
415
|
-
|
|
416
|
-
// Convert the Effekt String to a 0-terminated string
|
|
417
|
-
char* path_str = c_buffer_as_null_terminated_string(path);
|
|
418
|
-
erasePositive((struct Pos) path);
|
|
419
|
-
|
|
420
|
-
// Convert the Effekt String representing the opening mode to libuv flags
|
|
421
|
-
int32_t mode = modeToFlags(c_buffer_as_null_terminated_string(modeString));
|
|
422
|
-
erasePositive((struct Pos) modeString);
|
|
423
|
-
|
|
424
|
-
// Allocate Callbacks on the heap
|
|
425
|
-
Callbacks* callbacks = (Callbacks*)malloc(sizeof(Callbacks));
|
|
426
|
-
callbacks->on_success = *success;
|
|
427
|
-
callbacks->on_failure = *failure;
|
|
428
|
-
|
|
429
|
-
// Store the callbacks in the req's data field
|
|
430
|
-
req->data = callbacks;
|
|
431
|
-
|
|
432
|
-
// Get the default loop and call fs_open
|
|
433
|
-
uv_loop_t* loop = uv_default_loop();
|
|
434
|
-
|
|
435
|
-
int32_t result_i32 = uv_fs_open(loop, req, path_str, mode, (int32_t)permissions, c_file_open_handler);
|
|
436
|
-
int64_t result_i64 = (int64_t)result_i32;
|
|
437
|
-
|
|
438
|
-
// We can free the string, since libuv copies it into req
|
|
439
|
-
free(path_str);
|
|
440
|
-
|
|
441
|
-
return; // result_i64;
|
|
442
|
-
}
|
|
297
|
+
// Promises
|
|
298
|
+
// --------
|
|
443
299
|
|
|
300
|
+
typedef enum { UNRESOLVED, RESOLVED } promise_state_t;
|
|
444
301
|
|
|
445
|
-
|
|
446
|
-
|
|
302
|
+
typedef struct Listeners {
|
|
303
|
+
Stack head;
|
|
304
|
+
struct Listeners* tail;
|
|
305
|
+
} Listeners;
|
|
447
306
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
307
|
+
typedef struct {
|
|
308
|
+
uint64_t rc;
|
|
309
|
+
void* eraser;
|
|
310
|
+
promise_state_t state;
|
|
311
|
+
// state of {
|
|
312
|
+
// case UNRESOLVED => Possibly empty (head is NULL) list of listeners
|
|
313
|
+
// case RESOLVED => Pos (the result)
|
|
314
|
+
// }
|
|
315
|
+
union {
|
|
316
|
+
struct Pos value;
|
|
317
|
+
Listeners listeners;
|
|
318
|
+
} payload;
|
|
319
|
+
} Promise;
|
|
451
320
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
321
|
+
void c_promise_erase_listeners(void *envPtr) {
|
|
322
|
+
// envPtr points to a Promise _after_ the eraser, so let's adjust it to point to the promise.
|
|
323
|
+
Promise *promise = (Promise*) (envPtr - offsetof(Promise, state));
|
|
324
|
+
promise_state_t state = promise->state;
|
|
456
325
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
free(callbacks);
|
|
326
|
+
Stack head;
|
|
327
|
+
Listeners* tail;
|
|
328
|
+
Listeners* current;
|
|
461
329
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
330
|
+
switch (state) {
|
|
331
|
+
case UNRESOLVED:
|
|
332
|
+
head = promise->payload.listeners.head;
|
|
333
|
+
tail = promise->payload.listeners.tail;
|
|
334
|
+
if (head != NULL) {
|
|
335
|
+
// Erase head
|
|
336
|
+
eraseStack(head);
|
|
337
|
+
// Erase tail
|
|
338
|
+
current = tail;
|
|
339
|
+
while (current != NULL) {
|
|
340
|
+
head = current->head;
|
|
341
|
+
tail = current->tail;
|
|
342
|
+
free(current);
|
|
343
|
+
eraseStack(head);
|
|
344
|
+
current = tail;
|
|
345
|
+
};
|
|
346
|
+
};
|
|
347
|
+
break;
|
|
348
|
+
case RESOLVED:
|
|
349
|
+
erasePositive(promise->payload.value);
|
|
350
|
+
break;
|
|
468
351
|
}
|
|
469
352
|
}
|
|
470
353
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
uint8_t* buffer_data = c_buffer_bytes(buffer);
|
|
482
|
-
int32_t len = (int32_t)c_buffer_length(buffer);
|
|
483
|
-
|
|
484
|
-
uv_buf_t buf = uv_buf_init((char*)buffer_data, len);
|
|
485
|
-
|
|
486
|
-
uv_fs_t* req = (uv_fs_t*)malloc(sizeof(uv_fs_t));
|
|
487
|
-
|
|
488
|
-
// Allocate Callbacks on the heap
|
|
489
|
-
Callbacks* callbacks = (Callbacks*)malloc(sizeof(Callbacks));
|
|
490
|
-
callbacks->on_success = *success;
|
|
491
|
-
callbacks->on_failure = *failure;
|
|
492
|
-
|
|
493
|
-
// // Store the callbacks in the req's data field
|
|
494
|
-
req->data = callbacks;
|
|
495
|
-
|
|
496
|
-
// // Argument `1` here means: we pass exactly one buffer
|
|
497
|
-
uv_fs_read(loop, req, fd, &buf, 1, offset, c_file_read_handler);
|
|
354
|
+
void c_promise_resume_listeners(Listeners* listeners, struct Pos value) {
|
|
355
|
+
if (listeners != NULL) {
|
|
356
|
+
Stack head = listeners->head;
|
|
357
|
+
Listeners* tail = listeners->tail;
|
|
358
|
+
free(listeners);
|
|
359
|
+
c_promise_resume_listeners(tail, value);
|
|
360
|
+
sharePositive(value);
|
|
361
|
+
resume_Pos(head, value);
|
|
362
|
+
}
|
|
498
363
|
}
|
|
499
364
|
|
|
365
|
+
void c_promise_resolve(struct Pos promise, struct Pos value, Stack stack) {
|
|
366
|
+
Promise* p = (Promise*)promise.obj;
|
|
500
367
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
void c_file_write_handler(uv_fs_t* req) {
|
|
505
|
-
// Extract the result from the uv_fs_t structure
|
|
506
|
-
int64_t result = req->result;
|
|
368
|
+
Stack head;
|
|
369
|
+
Listeners* tail;
|
|
507
370
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
371
|
+
switch (p->state) {
|
|
372
|
+
case UNRESOLVED:
|
|
373
|
+
head = p->payload.listeners.head;
|
|
374
|
+
tail = p->payload.listeners.tail;
|
|
512
375
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
free(callbacks);
|
|
376
|
+
p->state = RESOLVED;
|
|
377
|
+
p->payload.value = value;
|
|
378
|
+
resume_Pos(stack, Unit);
|
|
517
379
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
380
|
+
if (head != NULL) {
|
|
381
|
+
// Execute tail
|
|
382
|
+
c_promise_resume_listeners(tail, value);
|
|
383
|
+
// Execute head
|
|
384
|
+
sharePositive(value);
|
|
385
|
+
resume_Pos(head, value);
|
|
386
|
+
};
|
|
387
|
+
break;
|
|
388
|
+
case RESOLVED:
|
|
389
|
+
erasePositive(promise);
|
|
390
|
+
erasePositive(value);
|
|
391
|
+
eraseStack(stack);
|
|
392
|
+
fprintf(stderr, "ERROR: Promise already resolved\n");
|
|
393
|
+
exit(1);
|
|
394
|
+
break;
|
|
524
395
|
}
|
|
396
|
+
// TODO stack overflow?
|
|
397
|
+
// We need to erase the promise now, since we consume it.
|
|
398
|
+
erasePositive(promise);
|
|
525
399
|
}
|
|
526
400
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
* stack-allocated). This is to work around an issue with the C ABI where
|
|
530
|
-
* late arguments are scrambled.
|
|
531
|
-
*/
|
|
532
|
-
void c_file_write(int32_t fd, struct Pos buffer, int64_t offset, struct Neg* success, struct Neg* failure) {
|
|
533
|
-
// Get the default loop
|
|
534
|
-
uv_loop_t* loop = uv_default_loop();
|
|
535
|
-
|
|
536
|
-
uint8_t* buffer_data = c_buffer_bytes(buffer);
|
|
537
|
-
int32_t len = (int32_t)c_buffer_length(buffer);
|
|
538
|
-
|
|
539
|
-
uv_buf_t buf = uv_buf_init((char*)buffer_data, len);
|
|
540
|
-
|
|
541
|
-
uv_fs_t* req = (uv_fs_t*)malloc(sizeof(uv_fs_t));
|
|
542
|
-
|
|
543
|
-
// Allocate Callbacks on the heap
|
|
544
|
-
Callbacks* callbacks = (Callbacks*)malloc(sizeof(Callbacks));
|
|
545
|
-
callbacks->on_success = *success;
|
|
546
|
-
callbacks->on_failure = *failure;
|
|
401
|
+
void c_promise_await(struct Pos promise, Stack stack) {
|
|
402
|
+
Promise* p = (Promise*)promise.obj;
|
|
547
403
|
|
|
548
|
-
|
|
549
|
-
|
|
404
|
+
Stack head;
|
|
405
|
+
Listeners* tail;
|
|
406
|
+
Listeners* node;
|
|
407
|
+
struct Pos value;
|
|
550
408
|
|
|
551
|
-
|
|
552
|
-
|
|
409
|
+
switch (p->state) {
|
|
410
|
+
case UNRESOLVED:
|
|
411
|
+
head = p->payload.listeners.head;
|
|
412
|
+
tail = p->payload.listeners.tail;
|
|
413
|
+
if (head != NULL) {
|
|
414
|
+
node = (Listeners*)malloc(sizeof(Listeners));
|
|
415
|
+
node->head = head;
|
|
416
|
+
node->tail = tail;
|
|
417
|
+
p->payload.listeners.head = stack;
|
|
418
|
+
p->payload.listeners.tail = node;
|
|
419
|
+
} else {
|
|
420
|
+
p->payload.listeners.head = stack;
|
|
421
|
+
};
|
|
422
|
+
break;
|
|
423
|
+
case RESOLVED:
|
|
424
|
+
value = p->payload.value;
|
|
425
|
+
sharePositive(value);
|
|
426
|
+
resume_Pos(stack, value);
|
|
427
|
+
break;
|
|
428
|
+
};
|
|
429
|
+
// TODO hmm, stack overflow?
|
|
430
|
+
erasePositive(promise);
|
|
553
431
|
}
|
|
554
432
|
|
|
555
|
-
|
|
556
|
-
|
|
433
|
+
struct Pos c_promise_make() {
|
|
434
|
+
Promise* promise = (Promise*)malloc(sizeof(Promise));
|
|
557
435
|
|
|
436
|
+
promise->rc = 0;
|
|
437
|
+
promise->eraser = c_promise_erase_listeners;
|
|
438
|
+
promise->state = UNRESOLVED;
|
|
439
|
+
promise->payload.listeners.head = NULL;
|
|
440
|
+
promise->payload.listeners.tail = NULL;
|
|
558
441
|
|
|
559
|
-
|
|
560
|
-
uv_fs_t req;
|
|
561
|
-
uv_loop_t* loop = uv_default_loop();
|
|
562
|
-
uv_fs_close(loop, &req, fd, NULL);
|
|
442
|
+
return (struct Pos) { .tag = 0, .obj = promise, };
|
|
563
443
|
}
|
|
564
444
|
|
|
565
445
|
|