@effekt-lang/effekt 0.2.1 → 0.3.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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +36 -0
  3. package/bin/effekt +0 -0
  4. package/bin/effekt.sh +2 -0
  5. package/libraries/chez/THIRD-PARTY.txt +11 -0
  6. package/libraries/chez/callcc/datatype.ss +188 -0
  7. package/libraries/chez/callcc/effekt.ss +31 -0
  8. package/libraries/chez/callcc/seq.ss +44 -0
  9. package/libraries/chez/callcc/seq0.ss +69 -0
  10. package/libraries/chez/callcc/tail.ss +76 -0
  11. package/libraries/chez/callcc/tail0.ss +89 -0
  12. package/libraries/chez/common/effekt_primitives.ss +105 -0
  13. package/libraries/chez/common/immutable/cslist.effekt +37 -0
  14. package/libraries/chez/common/mutable/dict.effekt +28 -0
  15. package/libraries/chez/common/text/pregexp.scm +772 -0
  16. package/libraries/chez/common/text/regex.effekt +31 -0
  17. package/libraries/chez/lift/effekt.ss +118 -0
  18. package/libraries/chez/monadic/effekt.ss +84 -0
  19. package/libraries/chez/monadic/seq0.ss +76 -0
  20. package/libraries/common/args.effekt +95 -0
  21. package/libraries/common/array.effekt +225 -0
  22. package/libraries/common/bench.effekt +60 -0
  23. package/libraries/common/buffer.effekt +123 -0
  24. package/libraries/common/bytes.effekt +125 -0
  25. package/libraries/common/dequeue.effekt +92 -0
  26. package/libraries/common/effekt.effekt +764 -0
  27. package/libraries/common/exception.effekt +122 -0
  28. package/libraries/common/io/console.effekt +66 -0
  29. package/libraries/common/io/error.effekt +365 -0
  30. package/libraries/common/io/files.effekt +282 -0
  31. package/libraries/common/io/network.effekt +105 -0
  32. package/libraries/common/io/time.effekt +15 -0
  33. package/libraries/common/io.effekt +158 -0
  34. package/libraries/common/list.effekt +687 -0
  35. package/libraries/common/option.effekt +72 -0
  36. package/libraries/common/process.effekt +10 -0
  37. package/libraries/common/queue.effekt +140 -0
  38. package/libraries/common/ref.effekt +63 -0
  39. package/libraries/common/result.effekt +45 -0
  40. package/libraries/common/seq.effekt +914 -0
  41. package/libraries/common/string.effekt +395 -0
  42. package/libraries/common/test.effekt +98 -0
  43. package/libraries/js/effekt_builtins.js +57 -0
  44. package/libraries/js/effekt_runtime.js +385 -0
  45. package/libraries/js/io.js +143 -0
  46. package/libraries/js/mutable/map.effekt +31 -0
  47. package/libraries/js/text/regex.effekt +33 -0
  48. package/libraries/js/unsafe/cont.effekt +11 -0
  49. package/libraries/js/web/dom.effekt +45 -0
  50. package/libraries/llvm/array.c +53 -0
  51. package/libraries/llvm/buffer.c +286 -0
  52. package/libraries/llvm/forward-declare-c.ll +43 -0
  53. package/libraries/llvm/hole.c +11 -0
  54. package/libraries/llvm/io.c +566 -0
  55. package/libraries/llvm/io.ll +19 -0
  56. package/libraries/llvm/main.c +41 -0
  57. package/libraries/llvm/ref.c +45 -0
  58. package/libraries/llvm/rts.ll +761 -0
  59. package/libraries/llvm/sanity.c +16 -0
  60. package/libraries/llvm/types.c +43 -0
  61. package/libraries/ml/effekt.sml +65 -0
  62. package/libraries/ml/internal/mllist.effekt +9 -0
  63. package/libraries/ml/internal/mloption.effekt +18 -0
  64. package/libraries/ml/random.effekt +85 -0
  65. package/libraries/ml/text/regex.effekt +102 -0
  66. package/licenses/THIRD-PARTY.txt +21 -0
  67. package/licenses/apache-2.0 - license-2.0.txt +202 -0
  68. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +61 -0
  69. package/licenses/kiama-license.txt +373 -0
  70. package/licenses/kiama-readme.txt +186 -0
  71. package/licenses/mit license - mit-license.html +1239 -0
  72. package/licenses/the apache software license, version 2.0 - license-2.0.txt +202 -0
  73. package/licenses/the bsd license - bsd-license.html +1237 -0
  74. package/licenses/the mit license - mit.html +1239 -0
  75. package/package.json +26 -18
@@ -0,0 +1,566 @@
1
+ #ifndef EFFEKT_IO_C
2
+ #define EFFEKT_IO_C
3
+
4
+ #include <uv.h>
5
+ #include <string.h> // to compare flag names
6
+
7
+ // Println
8
+ // -------
9
+
10
+ void c_io_println_Int(const Int n) {
11
+ printf("%" PRId64 "\n", n);
12
+ }
13
+
14
+ void c_io_println_Boolean(const struct Pos p) {
15
+ printf("%s\n", p.tag ? "true" : "false");
16
+ }
17
+
18
+ void c_io_println_Double(const Double x) {
19
+ printf("%g\n", x);
20
+ }
21
+
22
+ void c_io_println_String(String text) {
23
+ for (uint64_t j = 0; j < c_buffer_length(text); ++j)
24
+ putchar(c_buffer_bytes(text)[j]);
25
+ erasePositive(text);
26
+ putchar('\n');
27
+ }
28
+
29
+
30
+ // Promises
31
+ // --------
32
+
33
+ typedef enum { UNRESOLVED, RESOLVED, AWAITED } promise_state_t;
34
+
35
+ typedef struct Listeners {
36
+ struct Neg listener;
37
+ struct Listeners* next;
38
+ } Listeners;
39
+
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;
54
+
55
+ void c_promise_erase_listeners(struct Pos promise) {
56
+ Promise* p = (Promise*)promise.obj;
57
+
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;
77
+ }
78
+ }
79
+
80
+ void c_promise_resolve(struct Pos promise, struct Pos value) {
81
+ Promise* p = (Promise*)promise.obj;
82
+
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;
95
+
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
+ }
106
+ }
107
+ // do we need to erase promise now? Is it shared before?
108
+ erasePositive(promise);
109
+ }
110
+
111
+ void c_promise_await(struct Pos promise, struct Neg listener) {
112
+ Promise* p = (Promise*)promise.obj;
113
+
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
+ }
140
+ }
141
+ erasePositive(promise);
142
+ }
143
+
144
+
145
+ struct Pos c_promise_make() {
146
+ Promise* promise = (Promise*)malloc(sizeof(Promise));
147
+
148
+ promise->rc = 0;
149
+ promise->eraser = (void*)c_promise_erase_listeners;
150
+ promise->state = UNRESOLVED;
151
+ promise->payload.pos = Unit;
152
+
153
+ return (struct Pos) { .tag = 0, .obj = promise, };
154
+ }
155
+
156
+
157
+
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)
183
+
184
+
185
+ /**
186
+ * Maps the libuv error code to a stable (platform independent) numeric value.
187
+ *
188
+ * Tries to use most common errno integer values, but introduces fresh values (> 200)
189
+ * for those without common errno values.
190
+ */
191
+ int uv_error_to_errno(int uv_err) {
192
+ switch (uv_err) {
193
+ case UV_EPERM: return 1; // EPERM
194
+ case UV_ENOENT: return 2; // ENOENT
195
+ case UV_ESRCH: return 3; // ESRCH
196
+ case UV_EINTR: return 4; // EINTR
197
+ case UV_EIO: return 5; // EIO
198
+ case UV_ENXIO: return 6; // ENXIO
199
+ case UV_E2BIG: return 7; // E2BIG
200
+ case UV_EBADF: return 9; // EBADF
201
+ case UV_EAGAIN: return 11; // EAGAIN
202
+ case UV_ENOMEM: return 12; // ENOMEM
203
+ case UV_EACCES: return 13; // EACCES
204
+ case UV_EFAULT: return 14; // EFAULT
205
+ case UV_EBUSY: return 16; // EBUSY
206
+ case UV_EEXIST: return 17; // EEXIST
207
+ case UV_EXDEV: return 18; // EXDEV
208
+ case UV_ENODEV: return 19; // ENODEV
209
+ case UV_ENOTDIR: return 20; // ENOTDIR
210
+ case UV_EISDIR: return 21; // EISDIR
211
+ case UV_EINVAL: return 22; // EINVAL
212
+ case UV_ENFILE: return 23; // ENFILE
213
+ case UV_EMFILE: return 24; // EMFILE
214
+ case UV_ENOTTY: return 25; // ENOTTY
215
+ case UV_ETXTBSY: return 26; // ETXTBSY
216
+ case UV_EFBIG: return 27; // EFBIG
217
+ case UV_ENOSPC: return 28; // ENOSPC
218
+ case UV_ESPIPE: return 29; // ESPIPE
219
+ case UV_EROFS: return 30; // EROFS
220
+ case UV_EMLINK: return 31; // EMLINK
221
+ case UV_EPIPE: return 32; // EPIPE
222
+ case UV_ERANGE: return 34; // ERANGE
223
+ case UV_ENAMETOOLONG: return 36; // ENAMETOOLONG
224
+ case UV_ELOOP: return 40; // ELOOP
225
+ case UV_EOVERFLOW: return 75; // EOVERFLOW
226
+ case UV_EFTYPE: return 79; // EFTYPE
227
+ case UV_EILSEQ: return 84; // EILSEQ
228
+ case UV_ENOTSOCK: return 88; // ENOTSOCK
229
+ case UV_EDESTADDRREQ: return 89; // EDESTADDRREQ
230
+ case UV_EMSGSIZE: return 90; // EMSGSIZE
231
+ case UV_EPROTOTYPE: return 91; // EPROTOTYPE
232
+ case UV_ENOPROTOOPT: return 92; // ENOPROTOOPT
233
+ case UV_EPROTONOSUPPORT: return 93; // EPROTONOSUPPORT
234
+ case UV_ESOCKTNOSUPPORT: return 94; // ESOCKTNOSUPPORT
235
+ case UV_ENOTSUP: return 95; // EOPNOTSUPP
236
+ case UV_EAFNOSUPPORT: return 97; // EAFNOSUPPORT
237
+ case UV_EADDRINUSE: return 98; // EADDRINUSE
238
+ case UV_EADDRNOTAVAIL: return 99; // EADDRNOTAVAIL
239
+ case UV_ENETDOWN: return 100; // ENETDOWN
240
+ case UV_ENETUNREACH: return 101; // ENETUNREACH
241
+ case UV_ECONNABORTED: return 103; // ECONNABORTED
242
+ case UV_ECONNRESET: return 104; // ECONNRESET
243
+ case UV_ENOBUFS: return 105; // ENOBUFS
244
+ case UV_EISCONN: return 106; // EISCONN
245
+ case UV_ENOTCONN: return 107; // ENOTCONN
246
+ case UV_ETIMEDOUT: return 110; // ETIMEDOUT
247
+ case UV_ECONNREFUSED: return 111; // ECONNREFUSED
248
+ case UV_EHOSTUNREACH: return 113; // EHOSTUNREACH
249
+ case UV_EALREADY: return 114; // EALREADY
250
+ case UV_ECANCELED: return 125; // ECANCELED
251
+
252
+ case UV_EAI_ADDRFAMILY: return 200; // Fresh unique value
253
+ case UV_EAI_AGAIN: return 201; // Fresh unique value
254
+ case UV_EAI_BADFLAGS: return 202; // Fresh unique value
255
+ case UV_EAI_BADHINTS: return 203; // Fresh unique value
256
+ case UV_EAI_CANCELED: return 204; // Fresh unique value
257
+ case UV_EAI_FAIL: return 205; // Fresh unique value
258
+ case UV_EAI_FAMILY: return 206; // Fresh unique value
259
+ case UV_EAI_MEMORY: return 207; // Fresh unique value
260
+ case UV_EAI_NODATA: return 208; // Fresh unique value
261
+ case UV_EAI_NONAME: return 209; // Fresh unique value
262
+ case UV_EAI_OVERFLOW: return 210; // Fresh unique value
263
+ case UV_EAI_PROTOCOL: return 211; // Fresh unique value
264
+ case UV_EAI_SERVICE: return 212; // Fresh unique value
265
+ case UV_EAI_SOCKTYPE: return 213; // Fresh unique value
266
+ case UV_ECHARSET: return 215; // Fresh unique value
267
+ case UV_ENONET: return 216; // Fresh unique value
268
+ case UV_UNKNOWN: return 217; // Fresh unique value
269
+ case UV_EOF: return 218; // Fresh unique value
270
+
271
+ case UV_ESHUTDOWN: return 220; // Fresh unique value
272
+
273
+ // Not available in libuv1-dev on ubuntu
274
+ //case UV_EUNATCH: return 219; // Fresh unique value
275
+
276
+ default: return -1; // Unknown error
277
+ }
278
+ }
279
+
280
+
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
+ uv_timer_stop(handle);
312
+ free(handle->data);
313
+ free(handle);
314
+
315
+ // Finally call the callback
316
+ run(callback);
317
+ }
318
+
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
+ }
341
+
342
+
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
+ }
379
+ }
380
+
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
+ }
408
+ }
409
+
410
+
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
+ }
443
+
444
+
445
+ // Reading a File
446
+ // --------------
447
+
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;
451
+
452
+ // Load the callbacks
453
+ Callbacks* callbacks = (Callbacks*)req->data;
454
+ struct Neg success = callbacks->on_success;
455
+ struct Neg failure = callbacks->on_failure;
456
+
457
+ // Free request structure
458
+ uv_fs_req_cleanup(req);
459
+ free(req);
460
+ free(callbacks);
461
+
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));
468
+ }
469
+ }
470
+
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);
498
+ }
499
+
500
+
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;
507
+
508
+ // Load the callbacks
509
+ Callbacks* callbacks = (Callbacks*)req->data;
510
+ struct Neg success = callbacks->on_success;
511
+ struct Neg failure = callbacks->on_failure;
512
+
513
+ // Free request structure
514
+ uv_fs_req_cleanup(req);
515
+ free(req);
516
+ free(callbacks);
517
+
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));
524
+ }
525
+ }
526
+
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;
547
+
548
+ // Store the callbacks in the req's data field
549
+ req->data = callbacks;
550
+
551
+ // Argument `1` here means: we pass exactly one buffer
552
+ uv_fs_write(loop, req, fd, &buf, 1, offset, c_file_write_handler);
553
+ }
554
+
555
+ // ; Closing a File
556
+ // ; --------------
557
+
558
+
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);
563
+ }
564
+
565
+
566
+ #endif
@@ -0,0 +1,19 @@
1
+ declare i64 @uv_error_to_errno(i64)
2
+ declare ptr @uv_strerror(i32)
3
+
4
+ declare ptr @uv_default_loop()
5
+ declare i32 @uv_run(ptr, i32)
6
+ declare void @uv_stop(ptr)
7
+ declare void @uv_loop_close(ptr)
8
+
9
+ ; Helpers defined in C
10
+ declare void @c_timer_wait(i64, %Neg)
11
+ declare i64 @c_file_open(%Pos, %Pos, %Neg, %Neg)
12
+ declare void @c_file_close(%Pos)
13
+ declare void @c_file_read(i32, %Pos, i64, ptr, ptr)
14
+ declare void @c_file_write(i32, %Pos, i64, ptr, ptr)
15
+ declare %Pos @c_filedescriptor_show(%Pos)
16
+
17
+ declare %Pos @c_promise_make()
18
+ declare void @c_promise_resolve(%Pos, %Pos)
19
+ declare void @c_promise_await(%Pos, %Neg)
@@ -0,0 +1,41 @@
1
+ #include <errno.h>
2
+ #include <inttypes.h>
3
+ #include <limits.h>
4
+ #include <stdbool.h>
5
+ #include <stdint.h>
6
+ #include <stdio.h>
7
+ #include <stdlib.h>
8
+ #include <unistd.h>
9
+
10
+ #define DEBUG_REFCOUNT (false)
11
+
12
+ #include "sanity.c"
13
+ #include "types.c"
14
+ #include "buffer.c"
15
+ #include "io.c"
16
+ #include "hole.c"
17
+ #include "ref.c"
18
+ #include "array.c"
19
+
20
+
21
+ extern void effektMain();
22
+
23
+ int program_argc;
24
+ char** program_argv;
25
+
26
+ struct Pos c_get_arg(uint64_t idx) {
27
+ if(idx < (uint64_t)program_argc) {
28
+ return c_buffer_construct_from_null_terminated_string(program_argv[idx]);
29
+ } else {
30
+ return c_buffer_construct_zeroed(1);
31
+ }
32
+ }
33
+ uint64_t c_get_argc() {
34
+ return program_argc;
35
+ }
36
+
37
+ int main(int argc, char *argv[]) {
38
+ program_argc = argc;
39
+ program_argv = argv;
40
+ effektMain();
41
+ }
@@ -0,0 +1,45 @@
1
+ #ifndef EFFEKT_REF_C
2
+ #define EFFEKT_REF_C
3
+
4
+ /** We represent references like positive types.
5
+ * The tag is 0 and the obj points to memory with the following layout:
6
+ *
7
+ * +--[ Header ]--------------+------------+
8
+ * | ReferenceCount | Eraser | Field |
9
+ * +--------------------------+------------+
10
+ */
11
+
12
+ void c_ref_erase_field(void *envPtr) {
13
+ struct Pos *fieldPtr = envPtr;
14
+ struct Pos element = *fieldPtr;
15
+ erasePositive(element);
16
+ }
17
+
18
+ struct Pos c_ref_fresh(const struct Pos value) {
19
+ void *objPtr = malloc(sizeof(struct Header) + sizeof(struct Pos));
20
+ struct Header *headerPtr = objPtr;
21
+ struct Pos *fieldPtr = objPtr + sizeof(struct Header);
22
+ *headerPtr = (struct Header) { .rc = 0, .eraser = c_ref_erase_field, };
23
+ *fieldPtr = value;
24
+ return (struct Pos) {
25
+ .tag = 0,
26
+ .obj = objPtr,
27
+ };
28
+ }
29
+
30
+ struct Pos c_ref_get(const struct Pos ref) {
31
+ struct Pos *fieldPtr = ref.obj + sizeof(struct Header);
32
+ struct Pos element = *fieldPtr;
33
+ sharePositive(element);
34
+ return element;
35
+ }
36
+
37
+ struct Pos c_ref_set(const struct Pos ref, const struct Pos value) {
38
+ struct Pos *fieldPtr = ref.obj + sizeof(struct Header);
39
+ struct Pos element = *fieldPtr;
40
+ erasePositive(element);
41
+ *fieldPtr = value;
42
+ return Unit;
43
+ }
44
+
45
+ #endif