@effekt-lang/effekt 0.2.2 → 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.
- package/bin/effekt +0 -0
- package/bin/effekt.sh +1 -1
- package/libraries/chez/common/effekt_primitives.ss +10 -2
- package/libraries/chez/common/immutable/cslist.effekt +13 -7
- package/libraries/chez/common/mutable/dict.effekt +8 -10
- package/libraries/chez/common/text/regex.effekt +7 -9
- package/libraries/common/args.effekt +95 -0
- package/libraries/common/array.effekt +225 -0
- package/libraries/common/bench.effekt +60 -0
- package/libraries/common/buffer.effekt +123 -0
- package/libraries/common/bytes.effekt +125 -0
- package/libraries/{chez/common/immutable → common}/dequeue.effekt +18 -4
- package/libraries/common/effekt.effekt +764 -0
- package/libraries/common/exception.effekt +122 -0
- package/libraries/common/io/console.effekt +66 -0
- package/libraries/common/io/error.effekt +365 -0
- package/libraries/common/io/files.effekt +282 -0
- package/libraries/common/io/network.effekt +105 -0
- package/libraries/common/io/time.effekt +15 -0
- package/libraries/common/io.effekt +158 -0
- package/libraries/{llvm/immutable → common}/list.effekt +83 -74
- package/libraries/common/option.effekt +72 -0
- package/libraries/common/process.effekt +10 -0
- package/libraries/common/queue.effekt +140 -0
- package/libraries/common/ref.effekt +63 -0
- package/libraries/common/result.effekt +45 -0
- package/libraries/{ml/immutable → common}/seq.effekt +30 -19
- package/libraries/common/string.effekt +395 -0
- package/libraries/common/test.effekt +98 -0
- package/libraries/js/effekt_builtins.js +37 -6
- package/libraries/js/io.js +143 -0
- package/libraries/js/mutable/map.effekt +8 -9
- package/libraries/js/text/regex.effekt +7 -8
- package/libraries/js/unsafe/cont.effekt +2 -2
- package/libraries/js/web/dom.effekt +13 -13
- package/libraries/llvm/array.c +53 -0
- package/libraries/llvm/buffer.c +181 -76
- package/libraries/llvm/forward-declare-c.ll +27 -8
- package/libraries/llvm/io.c +543 -1
- package/libraries/llvm/io.ll +19 -0
- package/libraries/llvm/main.c +3 -1
- package/libraries/llvm/ref.c +45 -0
- package/libraries/llvm/rts.ll +496 -354
- package/libraries/llvm/types.c +23 -0
- package/libraries/ml/effekt.sml +2 -0
- package/libraries/ml/internal/mllist.effekt +9 -0
- package/libraries/ml/internal/mloption.effekt +18 -0
- package/libraries/ml/random.effekt +9 -9
- package/libraries/ml/text/regex.effekt +14 -19
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +2 -2
- package/licenses/mit license - mit-license.html +527 -57
- package/licenses/the bsd license - bsd-license.html +530 -55
- package/licenses/the mit license - mit.html +528 -58
- package/package.json +2 -2
- package/libraries/chez/callcc/effekt.effekt +0 -221
- package/libraries/chez/common/effekt_matching.ss +0 -100
- package/libraries/chez/common/immutable/list.effekt +0 -643
- package/libraries/chez/common/immutable/option.effekt +0 -39
- package/libraries/chez/common/immutable/result.effekt +0 -29
- package/libraries/chez/common/io/args.effekt +0 -20
- package/libraries/chez/common/mutable/array.effekt +0 -27
- package/libraries/chez/common/mutable/heap.effekt +0 -12
- package/libraries/chez/common/test.effekt +0 -59
- package/libraries/chez/common/text/string.effekt +0 -46
- package/libraries/chez/lift/effekt.effekt +0 -217
- package/libraries/chez/monadic/effekt.effekt +0 -218
- package/libraries/js/effekt.effekt +0 -284
- package/libraries/js/effekt_matching.js +0 -79
- package/libraries/js/immutable/dequeue.effekt +0 -78
- package/libraries/js/immutable/list.effekt +0 -643
- package/libraries/js/immutable/option.effekt +0 -49
- package/libraries/js/immutable/result.effekt +0 -29
- package/libraries/js/io/args.effekt +0 -9
- package/libraries/js/io/async.effekt +0 -28
- package/libraries/js/io/async.js +0 -2
- package/libraries/js/io/file.effekt +0 -50
- package/libraries/js/io/file_include.js +0 -13
- package/libraries/js/mutable/array.effekt +0 -98
- package/libraries/js/mutable/heap.effekt +0 -32
- package/libraries/js/test.effekt +0 -59
- package/libraries/js/text/string.effekt +0 -64
- package/libraries/llvm/effekt.effekt +0 -243
- package/libraries/llvm/immutable/option.effekt +0 -53
- package/libraries/llvm/immutable/result.effekt +0 -29
- package/libraries/llvm/io/args.effekt +0 -24
- package/libraries/llvm/text/string.effekt +0 -179
- package/libraries/ml/effekt.effekt +0 -267
- package/libraries/ml/immutable/dequeue.effekt +0 -81
- package/libraries/ml/immutable/list.effekt +0 -674
- package/libraries/ml/immutable/option.effekt +0 -53
- package/libraries/ml/immutable/result.effekt +0 -29
- package/libraries/ml/internal/option.effekt +0 -18
- package/libraries/ml/io/args.effekt +0 -41
- package/libraries/ml/mutable/array.effekt +0 -43
- package/libraries/ml/test.effekt +0 -60
- package/libraries/ml/text/string.effekt +0 -81
package/libraries/llvm/io.c
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
#ifndef EFFEKT_IO_C
|
|
2
2
|
#define EFFEKT_IO_C
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
#include <uv.h>
|
|
5
|
+
#include <string.h> // to compare flag names
|
|
6
|
+
|
|
7
|
+
// Println
|
|
8
|
+
// -------
|
|
5
9
|
|
|
6
10
|
void c_io_println_Int(const Int n) {
|
|
7
11
|
printf("%" PRId64 "\n", n);
|
|
@@ -18,7 +22,545 @@ void c_io_println_Double(const Double x) {
|
|
|
18
22
|
void c_io_println_String(String text) {
|
|
19
23
|
for (uint64_t j = 0; j < c_buffer_length(text); ++j)
|
|
20
24
|
putchar(c_buffer_bytes(text)[j]);
|
|
25
|
+
erasePositive(text);
|
|
21
26
|
putchar('\n');
|
|
22
27
|
}
|
|
23
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
|
+
|
|
24
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)
|
package/libraries/llvm/main.c
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
#include "buffer.c"
|
|
15
15
|
#include "io.c"
|
|
16
16
|
#include "hole.c"
|
|
17
|
+
#include "ref.c"
|
|
18
|
+
#include "array.c"
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
extern void effektMain();
|
|
@@ -22,7 +24,7 @@ int program_argc;
|
|
|
22
24
|
char** program_argv;
|
|
23
25
|
|
|
24
26
|
struct Pos c_get_arg(uint64_t idx) {
|
|
25
|
-
if(idx < program_argc) {
|
|
27
|
+
if(idx < (uint64_t)program_argc) {
|
|
26
28
|
return c_buffer_construct_from_null_terminated_string(program_argv[idx]);
|
|
27
29
|
} else {
|
|
28
30
|
return c_buffer_construct_zeroed(1);
|
|
@@ -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
|