@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.
Files changed (44) hide show
  1. package/README.md +6 -18
  2. package/bin/effekt +0 -0
  3. package/libraries/common/args.effekt +0 -27
  4. package/libraries/common/array.effekt +34 -63
  5. package/libraries/common/bench.effekt +40 -22
  6. package/libraries/common/buffer.effekt +8 -20
  7. package/libraries/common/bytes.effekt +5 -15
  8. package/libraries/common/dequeue.effekt +5 -5
  9. package/libraries/common/effekt.effekt +51 -92
  10. package/libraries/common/exception.effekt +0 -1
  11. package/libraries/common/io/console.effekt +30 -36
  12. package/libraries/common/io/error.effekt +131 -30
  13. package/libraries/common/io/filesystem.effekt +262 -0
  14. package/libraries/common/io/network.effekt +30 -54
  15. package/libraries/common/io/time.effekt +9 -12
  16. package/libraries/common/io.effekt +54 -124
  17. package/libraries/common/list.effekt +345 -327
  18. package/libraries/common/process.effekt +0 -1
  19. package/libraries/common/queue.effekt +1 -3
  20. package/libraries/common/ref.effekt +11 -24
  21. package/libraries/common/result.effekt +6 -14
  22. package/libraries/common/seq.effekt +28 -49
  23. package/libraries/common/string/tty.effekt +66 -0
  24. package/libraries/common/string.effekt +7 -49
  25. package/libraries/common/test.effekt +96 -34
  26. package/libraries/js/unsafe/cont.effekt +1 -1
  27. package/libraries/llvm/io.c +258 -378
  28. package/libraries/llvm/main.c +3 -0
  29. package/libraries/llvm/rts.ll +57 -38
  30. package/libraries/llvm/types.c +10 -1
  31. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
  32. package/licenses/mit license - mit-license.html +21 -20
  33. package/licenses/the bsd license - bsd-license.html +20 -21
  34. package/licenses/the mit license - mit.html +22 -21
  35. package/package.json +1 -1
  36. package/libraries/chez/lift/effekt.ss +0 -118
  37. package/libraries/common/io/files.effekt +0 -282
  38. package/libraries/js/io.js +0 -143
  39. package/libraries/llvm/io.ll +0 -19
  40. package/libraries/ml/effekt.sml +0 -65
  41. package/libraries/ml/internal/mllist.effekt +0 -9
  42. package/libraries/ml/internal/mloption.effekt +0 -18
  43. package/libraries/ml/random.effekt +0 -85
  44. package/libraries/ml/text/regex.effekt +0 -102
@@ -27,159 +27,153 @@ void c_io_println_String(String text) {
27
27
  }
28
28
 
29
29
 
30
- // Promises
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
- typedef struct Listeners {
36
- struct Neg listener;
37
- struct Listeners* next;
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
- typedef struct {
41
- uint64_t rc;
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
- void c_promise_erase_listeners(struct Pos promise) {
56
- Promise* p = (Promise*)promise.obj;
62
+ resume_Int(stack, result);
63
+ }
57
64
 
58
- switch (p->state) {
59
- case UNRESOLVED:
60
- return;
61
- case AWAITED:
62
- {
63
- Listeners* current = p->payload.listeners;
64
- // Free all listeners
65
- while (current != NULL) {
66
- Listeners* k = current;
67
- current = current->next;
68
- eraseNegative(k->listener);
69
- free(k);
70
- }
71
- p->payload.listeners = NULL;
72
- }
73
- return;
74
- case RESOLVED:
75
- erasePositive(p->payload.pos);
76
- return;
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 c_promise_resolve(struct Pos promise, struct Pos value) {
81
- Promise* p = (Promise*)promise.obj;
99
+ void c_fs_open(struct Pos path, struct Pos mode, Stack stack) {
82
100
 
83
- switch (p->state) {
84
- case UNRESOLVED:
85
- p->state = RESOLVED;
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
- // Call each listeners
97
- while (current != NULL) {
98
- sharePositive(value);
99
- run_Pos(current->listener, value);
100
- Listeners* temp = current;
101
- current = current->next;
102
- free(temp);
103
- }
104
- break;
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
- // do we need to erase promise now? Is it shared before?
108
- erasePositive(promise);
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 c_promise_await(struct Pos promise, struct Neg listener) {
112
- Promise* p = (Promise*)promise.obj;
126
+ void c_fs_read(Int fd, struct Pos buffer, Int offset, Stack stack) {
113
127
 
114
- switch (p->state) {
115
- case UNRESOLVED:
116
- p->state = AWAITED;
117
- p->payload.listeners = (Listeners*)malloc(sizeof(Listeners));
118
- p->payload.listeners->listener = listener;
119
- p->payload.listeners->next = NULL;
120
- break;
121
- case RESOLVED:
122
- run_Pos(listener, p->payload.pos);
123
- break;
124
- case AWAITED: {
125
- Listeners* new_node = (Listeners*)malloc(sizeof(Listeners));
126
- new_node->listener = listener;
127
- new_node->next = NULL;
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
- struct Pos c_promise_make() {
146
- Promise* promise = (Promise*)malloc(sizeof(Promise));
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
- promise->rc = 0;
149
- promise->eraser = (void*)c_promise_erase_listeners;
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
- return (struct Pos) { .tag = 0, .obj = promise, };
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
- // Lib UV Bindings
159
- // ---------------
160
- // Ideas behind the LLVM / libuv implementation.
161
- //
162
- // Share memory between Effekt-buffers and libuv buffers
163
- // -----------------------------------------------------
164
- // A libuv buffer is a {ptr, i64} where i64 is the capacity
165
- // while our buffer (from buffer.c, which is ref-counted) is a %Pos with a
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
- int uv_error_to_errno(int uv_err) {
192
- switch (uv_err) {
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
- free(handle->data);
313
- free(handle);
278
+ uv_close((uv_handle_t*)handle, (uv_close_cb)free);
314
279
 
315
- // Finally call the callback
316
- run(callback);
280
+ resume_Pos(stack, Unit);
317
281
  }
318
282
 
319
- void c_timer_wait(int64_t n, struct Neg callback) {
320
-
321
- // Get the default loop
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
- // Opening a File
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
- typedef struct Callbacks {
382
- struct Neg on_success;
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
- void c_file_open(struct Pos path, struct Pos modeString, struct Neg* success, struct Neg* failure) {
412
- int permissions = 0666; // rw-rw-rw- permissions
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
- // Reading a File
446
- // --------------
302
+ typedef struct Listeners {
303
+ Stack head;
304
+ struct Listeners* tail;
305
+ } Listeners;
447
306
 
448
- void c_file_read_handler(uv_fs_t* req) {
449
- // Extract the file descriptor from the uv_fs_t structure
450
- int64_t result = req->result;
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
- // Load the callbacks
453
- Callbacks* callbacks = (Callbacks*)req->data;
454
- struct Neg success = callbacks->on_success;
455
- struct Neg failure = callbacks->on_failure;
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
- // Free request structure
458
- uv_fs_req_cleanup(req);
459
- free(req);
460
- free(callbacks);
326
+ Stack head;
327
+ Listeners* tail;
328
+ Listeners* current;
461
329
 
462
- if (result >= 0) {
463
- eraseNegative(failure);
464
- run_i64(success, result);
465
- } else {
466
- eraseNegative(success);
467
- run_i64(failure, uv_error_to_errno(result));
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
- * Here we require success and failure to be passed by reference (can be
473
- * stack-allocated). This is to work around an issue with the C ABI where
474
- * late arguments are scrambled.
475
- */
476
- void c_file_read(int32_t fd, struct Pos buffer, int64_t offset, struct Neg* success, struct Neg* failure) {
477
-
478
- // Get the default loop
479
- uv_loop_t* loop = uv_default_loop();
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
- // Writing to a File
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
- // Load the callbacks
509
- Callbacks* callbacks = (Callbacks*)req->data;
510
- struct Neg success = callbacks->on_success;
511
- struct Neg failure = callbacks->on_failure;
371
+ switch (p->state) {
372
+ case UNRESOLVED:
373
+ head = p->payload.listeners.head;
374
+ tail = p->payload.listeners.tail;
512
375
 
513
- // Free request structure
514
- uv_fs_req_cleanup(req);
515
- free(req);
516
- free(callbacks);
376
+ p->state = RESOLVED;
377
+ p->payload.value = value;
378
+ resume_Pos(stack, Unit);
517
379
 
518
- if (result >= 0) {
519
- eraseNegative(failure);
520
- run_i64(success, result);
521
- } else {
522
- eraseNegative(success);
523
- run_i64(failure, uv_error_to_errno(result));
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
- * Here we require success and failure to be passed by reference (can be
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
- // Store the callbacks in the req's data field
549
- req->data = callbacks;
404
+ Stack head;
405
+ Listeners* tail;
406
+ Listeners* node;
407
+ struct Pos value;
550
408
 
551
- // Argument `1` here means: we pass exactly one buffer
552
- uv_fs_write(loop, req, fd, &buf, 1, offset, c_file_write_handler);
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
- // ; Closing a File
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
- void c_file_close(int32_t fd) {
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