@effekt-lang/effekt 0.21.0 → 0.23.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/libraries/common/array.effekt +381 -7
- package/libraries/common/bytearray.effekt +9 -0
- package/libraries/common/exception.effekt +1 -1
- package/libraries/common/io/filesystem.effekt +18 -0
- package/libraries/common/resizable_array.effekt +1 -1
- package/libraries/common/stream.effekt +8 -3
- package/libraries/llvm/file.c +1 -0
- package/libraries/llvm/io.c +25 -2
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +7 -5
- package/licenses/mit license - mit-license.html +38 -32
- package/licenses/the bsd license - bsd-license.html +38 -32
- package/licenses/the mit license - mit.html +39 -33
- package/package.json +1 -1
package/bin/effekt
CHANGED
|
Binary file
|
|
@@ -3,6 +3,7 @@ module array
|
|
|
3
3
|
import effekt
|
|
4
4
|
import exception
|
|
5
5
|
import list
|
|
6
|
+
import option
|
|
6
7
|
|
|
7
8
|
/// A mutable 0-indexed fixed-sized array.
|
|
8
9
|
extern type Array[T]
|
|
@@ -18,12 +19,17 @@ extern global def allocate[T](size: Int): Array[T] =
|
|
|
18
19
|
"""
|
|
19
20
|
vm "array::allocate(Int)"
|
|
20
21
|
|
|
22
|
+
/// Fills a given array in-place.
|
|
23
|
+
def fill[T](arr: Array[T], filler: T): Unit = {
|
|
24
|
+
arr.foreachIndex { (idx, _) =>
|
|
25
|
+
arr.unsafeSet(idx, filler)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
/// Creates a new Array of size `size` filled with the value `init`
|
|
22
30
|
def array[T](size: Int, init: T): Array[T] = {
|
|
23
31
|
val arr = allocate[T](size);
|
|
24
|
-
|
|
25
|
-
unsafeSet(arr, i, init)
|
|
26
|
-
};
|
|
32
|
+
arr.fill(init)
|
|
27
33
|
arr
|
|
28
34
|
}
|
|
29
35
|
|
|
@@ -81,8 +87,6 @@ extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit =
|
|
|
81
87
|
"""
|
|
82
88
|
vm "array::unsafeSet[T](Array[T], Int, T)"
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
86
90
|
// Derived operations:
|
|
87
91
|
|
|
88
92
|
/// Gets the element of the `arr` at given `index` in constant time,
|
|
@@ -107,6 +111,9 @@ def build[T](size: Int) { index: Int => T }: Array[T] = {
|
|
|
107
111
|
arr
|
|
108
112
|
}
|
|
109
113
|
|
|
114
|
+
/// Resizes an array to a given size.
|
|
115
|
+
///
|
|
116
|
+
/// O(N + M)
|
|
110
117
|
def resize[T](source: Array[T], size: Int): Array[T] = {
|
|
111
118
|
val target = allocate(size)
|
|
112
119
|
val n = min(source.size, target.size)
|
|
@@ -147,6 +154,27 @@ def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int):
|
|
|
147
154
|
|
|
148
155
|
// Utility functions:
|
|
149
156
|
|
|
157
|
+
/// Swap the value at index i with that at index j.
|
|
158
|
+
/// Warning: undefined behaviour if the indices are out bound.
|
|
159
|
+
///
|
|
160
|
+
/// O(1)
|
|
161
|
+
def unsafeSwap[A](arr: Array[A], i: Int, j: Int): Unit = {
|
|
162
|
+
val tmp = arr.unsafeGet(i)
|
|
163
|
+
arr.unsafeSet(i, arr.unsafeGet(j))
|
|
164
|
+
arr.unsafeSet(j, tmp)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/// Swap the value at index i with that at index j.
|
|
168
|
+
///
|
|
169
|
+
/// O(1)
|
|
170
|
+
def swap[A](arr: Array[A], i: Int, j: Int): Unit / Exception[OutOfBounds] = {
|
|
171
|
+
if (i < 0 || i >= arr.size || j < 0 || j >= arr.size) do raise(OutOfBounds(), "Index out of bounds")
|
|
172
|
+
arr.unsafeSwap(i, j)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/// Converts the given array into a list.
|
|
176
|
+
///
|
|
177
|
+
/// O(N)
|
|
150
178
|
def toList[T](arr: Array[T]): List[T] = {
|
|
151
179
|
var i = arr.size - 1;
|
|
152
180
|
var l = Nil[T]()
|
|
@@ -157,34 +185,380 @@ def toList[T](arr: Array[T]): List[T] = {
|
|
|
157
185
|
l
|
|
158
186
|
}
|
|
159
187
|
|
|
188
|
+
/// Traverse an array, applying the given action on every element.
|
|
189
|
+
///
|
|
190
|
+
/// O(N)
|
|
160
191
|
def foreach[T](arr: Array[T]){ action: T => Unit }: Unit =
|
|
161
192
|
each(0, arr.size) { i =>
|
|
162
193
|
action(arr.unsafeGet(i))
|
|
163
194
|
}
|
|
164
195
|
|
|
196
|
+
/// Traverse an array, applying the given action on every element.
|
|
197
|
+
///
|
|
198
|
+
/// O(N)
|
|
165
199
|
def foreach[T](arr: Array[T]){ action: (T) {Control} => Unit }: Unit =
|
|
166
200
|
each(0, arr.size) { (i) {label} =>
|
|
167
201
|
action(arr.unsafeGet(i)) {label}
|
|
168
202
|
}
|
|
169
203
|
|
|
204
|
+
/// Traverse an array, applying the given action on every element and its (zero-based) index.
|
|
205
|
+
///
|
|
206
|
+
/// O(N)
|
|
170
207
|
def foreachIndex[T](arr: Array[T]){ action: (Int, T) => Unit }: Unit =
|
|
171
208
|
each(0, arr.size) { i =>
|
|
172
209
|
action(i, arr.unsafeGet(i))
|
|
173
210
|
}
|
|
174
211
|
|
|
212
|
+
/// Traverse an array, applying the given action on every element and its (zero-based) index.
|
|
213
|
+
///
|
|
214
|
+
/// O(N)
|
|
175
215
|
def foreachIndex[T](arr: Array[T]){ action: (Int, T) {Control} => Unit }: Unit =
|
|
176
216
|
each(0, arr.size) { (i) {label} =>
|
|
177
217
|
action(i, arr.unsafeGet(i)) {label}
|
|
178
218
|
}
|
|
179
219
|
|
|
180
|
-
|
|
220
|
+
/// Sum the elements of the array.
|
|
221
|
+
///
|
|
222
|
+
/// O(N)
|
|
223
|
+
def sum(arr: Array[Int]): Int = {
|
|
181
224
|
var acc = 0
|
|
182
|
-
|
|
225
|
+
arr.foreach { x =>
|
|
183
226
|
acc = acc + x
|
|
184
227
|
}
|
|
185
228
|
acc
|
|
186
229
|
}
|
|
187
230
|
|
|
231
|
+
/// Checks whether two given arrays are equal with respect to an equalty funciton defined on their element.
|
|
232
|
+
///
|
|
233
|
+
/// O(N)
|
|
234
|
+
def equals[A](this: Array[A], other: Array[A]) { eq: (A, A) => Bool }: Bool = {
|
|
235
|
+
if (this.size != other.size) false
|
|
236
|
+
else {
|
|
237
|
+
var res = true
|
|
238
|
+
this.foreachIndex { (idx, elem) {label} =>
|
|
239
|
+
if (not(eq(elem, other.unsafeGet(idx)))) {
|
|
240
|
+
res = false
|
|
241
|
+
label.break()
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
res
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/// Map a function `f` over the elements in a given array.
|
|
249
|
+
/// Modifies the array in-place.
|
|
250
|
+
///
|
|
251
|
+
/// O(N)
|
|
252
|
+
def map[A](arr: Array[A]) { f: A => A }: Unit = {
|
|
253
|
+
arr.foreachIndex { (idx, elem) =>
|
|
254
|
+
arr.unsafeSet(idx, f(arr.unsafeGet(idx)))
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/// Map a function over elements.
|
|
259
|
+
/// Allocates a new array of the same size.
|
|
260
|
+
///
|
|
261
|
+
/// O(N)
|
|
262
|
+
def mapped[A, B](arr: Array[A]) { f: A => B }: Array[B] = {
|
|
263
|
+
val res = allocate(arr.size)
|
|
264
|
+
arr.foreachIndex { (idx, elem) =>
|
|
265
|
+
res.unsafeSet(idx, f(arr.unsafeGet(idx)))
|
|
266
|
+
}
|
|
267
|
+
res
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/// Reverses an array in-place.
|
|
271
|
+
///
|
|
272
|
+
/// O(N)
|
|
273
|
+
def reverse[A](arr: Array[A]): Unit = {
|
|
274
|
+
val size = arr.size()
|
|
275
|
+
val mid = size / 2
|
|
276
|
+
|
|
277
|
+
// Swap elements from start and end, moving towards the middle
|
|
278
|
+
each(0, mid) { i =>
|
|
279
|
+
val temp = arr.unsafeGet(i)
|
|
280
|
+
val j = size - 1 - i
|
|
281
|
+
val other = arr.unsafeGet(j)
|
|
282
|
+
arr.unsafeSet(i, other)
|
|
283
|
+
arr.unsafeSet(j, temp)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/// Creates a new array with elements in reverse order.
|
|
287
|
+
///
|
|
288
|
+
/// O(N)
|
|
289
|
+
def reversed[A](arr: Array[A]): Array[A] = {
|
|
290
|
+
val size = arr.size()
|
|
291
|
+
val result = allocate[A](size)
|
|
292
|
+
|
|
293
|
+
// Copy elements in reverse order to new array
|
|
294
|
+
each(0, size) { i =>
|
|
295
|
+
val value = arr.unsafeGet(i)
|
|
296
|
+
result.unsafeSet(size - 1 - i, value)
|
|
297
|
+
}
|
|
298
|
+
result
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/// Fold an array using `f`, starting from the left given a starting value.
|
|
302
|
+
///
|
|
303
|
+
/// O(N)
|
|
304
|
+
def foldLeft[A, B](arr: Array[A], init: B) { f: (B, A) => B }: B = {
|
|
305
|
+
var acc = init;
|
|
306
|
+
arr.foreach { x => acc = f(acc, x) };
|
|
307
|
+
acc
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/// Fold an array using `f`, starting from the right given a starting value.
|
|
311
|
+
///
|
|
312
|
+
/// O(N)
|
|
313
|
+
def foldRight[A, B](arr: Array[A], init: B) { f: (A, B) => B }: B = {
|
|
314
|
+
var acc = init;
|
|
315
|
+
arr.reversed.foreach { x => acc = f(x, acc) };
|
|
316
|
+
acc
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/// Filters a given array with respect to a given predicate such that a
|
|
320
|
+
/// new array containing all the elements for which the predicate
|
|
321
|
+
/// holds is allocated.
|
|
322
|
+
///
|
|
323
|
+
/// O(N)
|
|
324
|
+
def filtered[A](arr: Array[A]) { shouldKeep: A => Bool }: Array[A] = {
|
|
325
|
+
val res = arr.copy()
|
|
326
|
+
var idx = 0
|
|
327
|
+
arr.foreach { x =>
|
|
328
|
+
if (shouldKeep(x)) {
|
|
329
|
+
res.unsafeSet(idx, x)
|
|
330
|
+
idx = idx + 1
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
res.resize(idx)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/// Check if predicate is true for all elements.
|
|
337
|
+
///
|
|
338
|
+
/// O(N)
|
|
339
|
+
def all[A](arr: Array[A]) { predicate: A => Bool }: Bool = {
|
|
340
|
+
var result = true
|
|
341
|
+
arr.foreach { (x) {label} =>
|
|
342
|
+
if (not(predicate(x))) {
|
|
343
|
+
result = false
|
|
344
|
+
label.break()
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
result
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/// Check if predicate is true for at least one element.
|
|
351
|
+
///
|
|
352
|
+
/// O(N)
|
|
353
|
+
def any[A](arr: Array[A]) { predicate: A => Bool }: Bool = {
|
|
354
|
+
not(arr.all { x => not(predicate(x)) })
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/// Count elements satisfying the predicate.
|
|
358
|
+
///
|
|
359
|
+
/// O(N)
|
|
360
|
+
def count[A](arr: Array[A]) { predicate: A => Bool }: Int = {
|
|
361
|
+
var count = 0
|
|
362
|
+
arr.foreach { x =>
|
|
363
|
+
if (predicate(x)) count = count + 1
|
|
364
|
+
}
|
|
365
|
+
count
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/// Take first n elements.
|
|
369
|
+
/// Returns a new array.
|
|
370
|
+
///
|
|
371
|
+
/// O(N)
|
|
372
|
+
def take[A](arr: Array[A], n: Int): Array[A] = {
|
|
373
|
+
val len = min(max(0, n), arr.size)
|
|
374
|
+
val result = allocate[A](len)
|
|
375
|
+
each(0, len) { i =>
|
|
376
|
+
result.unsafeSet(i, arr.unsafeGet(i))
|
|
377
|
+
}
|
|
378
|
+
result
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Drop first n elements.
|
|
382
|
+
/// Returns a new array.
|
|
383
|
+
///
|
|
384
|
+
/// O(N)
|
|
385
|
+
def drop[A](arr: Array[A], n: Int): Array[A] = {
|
|
386
|
+
val start = min(max(0, n), arr.size)
|
|
387
|
+
val len = arr.size - start
|
|
388
|
+
val result = allocate[A](len)
|
|
389
|
+
each(0, len) { i =>
|
|
390
|
+
result.unsafeSet(i, arr.unsafeGet(i + start))
|
|
391
|
+
}
|
|
392
|
+
result
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/// Return a slice from start (inclusive) to end (exclusive).
|
|
396
|
+
/// Returns a new array.
|
|
397
|
+
///
|
|
398
|
+
/// O(N)
|
|
399
|
+
def sliced[A](arr: Array[A], start: Int, end: Int): Array[A] = {
|
|
400
|
+
val validStart = min(max(0, start), arr.size)
|
|
401
|
+
val validEnd = min(max(validStart, end), arr.size)
|
|
402
|
+
val len = validEnd - validStart
|
|
403
|
+
val result = allocate[A](len)
|
|
404
|
+
each(0, len) { i =>
|
|
405
|
+
result.unsafeSet(i, arr.unsafeGet(i + validStart))
|
|
406
|
+
}
|
|
407
|
+
result
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/// Zip two arrays into an array of pairs.
|
|
411
|
+
/// Length is minimum of input lengths.
|
|
412
|
+
///
|
|
413
|
+
/// O(min(N, M))
|
|
414
|
+
def zipped[A, B](this: Array[A], other: Array[B]): Array[(A, B)] = {
|
|
415
|
+
val len = min(this.size, other.size)
|
|
416
|
+
val result = allocate[(A, B)](len)
|
|
417
|
+
each(0, len) { i =>
|
|
418
|
+
result.unsafeSet(i, (this.unsafeGet(i), other.unsafeGet(i)))
|
|
419
|
+
}
|
|
420
|
+
result
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/// Combine two arrays using given function.
|
|
424
|
+
/// Length is minimum of input lengths.
|
|
425
|
+
///
|
|
426
|
+
/// O(min(N, M))
|
|
427
|
+
def zippedWith[A, B, C](this: Array[A], other: Array[B]) { f: (A, B) => C }: Array[C] = {
|
|
428
|
+
val len = min(this.size, other.size)
|
|
429
|
+
val result = allocate[C](len)
|
|
430
|
+
each(0, len) { i =>
|
|
431
|
+
result.unsafeSet(i, f(this.unsafeGet(i), other.unsafeGet(i)))
|
|
432
|
+
}
|
|
433
|
+
result
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/// Produce a pair of arrays from an array of pairs.
|
|
437
|
+
/// Allocates two new arrays as a result.
|
|
438
|
+
///
|
|
439
|
+
/// O(N)
|
|
440
|
+
def unzipped[A, B](arr: Array[(A, B)]): (Array[A], Array[B]) = {
|
|
441
|
+
val arr1 = allocate(arr.size)
|
|
442
|
+
val arr2 = allocate(arr.size)
|
|
443
|
+
arr.foreachIndex { (idx, tpl) =>
|
|
444
|
+
val (x, y) = tpl
|
|
445
|
+
arr1.unsafeSet(idx, x)
|
|
446
|
+
arr2.unsafeSet(idx, y)
|
|
447
|
+
}
|
|
448
|
+
(arr1, arr2)
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/// Partition a given array into two arrays.
|
|
452
|
+
/// The left array contains the elements that satsify the predicate,
|
|
453
|
+
/// the right array contains the elements that do not.
|
|
454
|
+
///
|
|
455
|
+
/// O(N)
|
|
456
|
+
def partioned[A](arr: Array[A]) { pred: A => Bool }: (Array[A], Array[A]) = {
|
|
457
|
+
val tcases = arr.copy()
|
|
458
|
+
val fcases = arr.copy()
|
|
459
|
+
var tidx = 0
|
|
460
|
+
var fidx = 0
|
|
461
|
+
arr.foreach { x =>
|
|
462
|
+
if (pred(x)) {
|
|
463
|
+
tcases.unsafeSet(tidx, x)
|
|
464
|
+
tidx = tidx + 1
|
|
465
|
+
} else {
|
|
466
|
+
fcases.unsafeSet(fidx, x)
|
|
467
|
+
fidx = fidx + 1
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
(tcases.resize(tidx), fcases.resize(fidx))
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/// Get the _first_ index of the last occurance of `elem`, if there is any.
|
|
474
|
+
///
|
|
475
|
+
/// O(N)
|
|
476
|
+
def indexOf[A](arr: Array[A], toFind: A) { eq: (A, A) => Bool }: Option[Int] = {
|
|
477
|
+
var found = None[Int]()
|
|
478
|
+
arr.foreachIndex { (idx, elem) {label} =>
|
|
479
|
+
if (eq(elem, toFind) && found.isEmpty) {
|
|
480
|
+
found = Some(idx)
|
|
481
|
+
label.break()
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
found
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/// Get the _last_ index of the last occurance of `elem`, if there is any.
|
|
488
|
+
///
|
|
489
|
+
/// O(N)
|
|
490
|
+
def lastIndexOf[A](arr: Array[A], toFind: A) { eq: (A, A) => Bool }: Option[Int] = {
|
|
491
|
+
var lastFound = None[Int]()
|
|
492
|
+
arr.foreachIndex { (idx, elem) =>
|
|
493
|
+
if (eq(elem, toFind)) {
|
|
494
|
+
lastFound = Some(idx)
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
lastFound
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/// Perform binary search to find the index of a given element.
|
|
501
|
+
///
|
|
502
|
+
/// O(log N)
|
|
503
|
+
def binarySearch[A](arr: Array[A], toFind: A) { ord: (A, A) => Ordering }: Option[Int] = {
|
|
504
|
+
def binarySearch(lowerIdx: Int, upperIdx: Int): Option[Int] = {
|
|
505
|
+
if (lowerIdx > upperIdx) None()
|
|
506
|
+
else {
|
|
507
|
+
val mid = lowerIdx + (upperIdx - lowerIdx) / 2
|
|
508
|
+
val current = arr.unsafeGet(mid)
|
|
509
|
+
ord(current, toFind) match {
|
|
510
|
+
case Less() => binarySearch(mid + 1, upperIdx)
|
|
511
|
+
case Greater() => binarySearch(lowerIdx, mid - 1)
|
|
512
|
+
case Equal() => Some(mid)
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
binarySearch(0, arr.size - 1)
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/// Sort an array in-place using provided comparison function.
|
|
520
|
+
/// Note: sort is unstable since it uses QuickSort (unlike list::sortBy)
|
|
521
|
+
///
|
|
522
|
+
/// O(N log N) average case
|
|
523
|
+
def sort[A](arr: Array[A]) { ord: (A, A) => Ordering }: Unit = {
|
|
524
|
+
def partition(low: Int, high: Int): Int = {
|
|
525
|
+
val pivot = arr.unsafeGet(high)
|
|
526
|
+
var i = low - 1
|
|
527
|
+
|
|
528
|
+
each(low, high) { j =>
|
|
529
|
+
ord(arr.unsafeGet(j), pivot) match {
|
|
530
|
+
case Less() =>
|
|
531
|
+
i = i + 1
|
|
532
|
+
unsafeSwap(arr, i, j)
|
|
533
|
+
case _ => ()
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
unsafeSwap(arr, i + 1, high)
|
|
537
|
+
i + 1
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
def quickSort(low: Int, high: Int): Unit = {
|
|
541
|
+
if (low < high) {
|
|
542
|
+
val par = partition(low, high)
|
|
543
|
+
quickSort(low, par - 1)
|
|
544
|
+
quickSort(par + 1, high)
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
quickSort(0, arr.size - 1)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/// Sort an array using provided comparison function.
|
|
552
|
+
/// A newly allocated sorted array is returned as result, i.e., the sorting is not in-place.
|
|
553
|
+
/// Note: sort is unstable since it uses QuickSort (unlike list::sortBy)
|
|
554
|
+
///
|
|
555
|
+
/// O(N log N) average case
|
|
556
|
+
def sorted[A](arr: Array[A]) { ord: (A, A) => Ordering }: Array[A] = {
|
|
557
|
+
val res = arr.copy()
|
|
558
|
+
res.sort { ord }
|
|
559
|
+
res
|
|
560
|
+
}
|
|
561
|
+
|
|
188
562
|
// Show Instances
|
|
189
563
|
// --------------
|
|
190
564
|
|
|
@@ -41,6 +41,15 @@ extern global def unsafeSet(arr: ByteArray, index: Int, value: Byte): Unit =
|
|
|
41
41
|
"""
|
|
42
42
|
chez "(bytevector-u8-set! ${arr} ${index} ${value})"
|
|
43
43
|
|
|
44
|
+
/// Creates a new ByteArray of size `size` filled with the value `init`
|
|
45
|
+
def bytearray(size: Int, init: Byte): ByteArray = {
|
|
46
|
+
val arr = allocate(size);
|
|
47
|
+
each(0, size) { i =>
|
|
48
|
+
unsafeSet(arr, i, init)
|
|
49
|
+
};
|
|
50
|
+
arr
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
def resize(source: ByteArray, size: Int): ByteArray = {
|
|
45
54
|
val target = allocate(size)
|
|
46
55
|
val n = min(source.size, target.size)
|
|
@@ -50,7 +50,7 @@ def wrongFormat(msg: String): Nothing / Exception[WrongFormat] =
|
|
|
50
50
|
/**
|
|
51
51
|
* A fatal runtime error that cannot be caught
|
|
52
52
|
*/
|
|
53
|
-
extern io def panic
|
|
53
|
+
extern io def panic(msg: String): Nothing =
|
|
54
54
|
js "(function() { throw ${msg} })()"
|
|
55
55
|
chez "(raise ${msg})"
|
|
56
56
|
llvm """
|
|
@@ -109,6 +109,10 @@ def close(file: File): Unit / Exception[IOError] = {
|
|
|
109
109
|
internal::checkResult(internal::close(file)); ()
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
def mkdir(path: String): Unit / Exception[IOError] = {
|
|
113
|
+
internal::checkResult(internal::mkdir(path)); ()
|
|
114
|
+
}
|
|
115
|
+
|
|
112
116
|
namespace internal {
|
|
113
117
|
|
|
114
118
|
extern js """
|
|
@@ -149,6 +153,12 @@ namespace internal {
|
|
|
149
153
|
if (err) { callback(err.errno) } else { callback(0) }
|
|
150
154
|
})
|
|
151
155
|
}
|
|
156
|
+
|
|
157
|
+
function mkdir(path, callback) {
|
|
158
|
+
fs.mkdir(path, (err) => {
|
|
159
|
+
if (err) { callback(err.errno) } else { callback(0) }
|
|
160
|
+
})
|
|
161
|
+
}
|
|
152
162
|
"""
|
|
153
163
|
|
|
154
164
|
extern llvm """
|
|
@@ -158,6 +168,7 @@ namespace internal {
|
|
|
158
168
|
declare void @c_fs_read(%Int, %Pos, %Int, %Int, %Int, %Stack)
|
|
159
169
|
declare void @c_fs_write(%Int, %Pos, %Int, %Int, %Int, %Stack)
|
|
160
170
|
declare void @c_fs_close(%Int, %Stack)
|
|
171
|
+
declare void @c_fs_mkdir(%Pos, %Stack)
|
|
161
172
|
"""
|
|
162
173
|
|
|
163
174
|
extern async def openForReading(path: String): Int =
|
|
@@ -204,6 +215,13 @@ namespace internal {
|
|
|
204
215
|
ret void
|
|
205
216
|
"""
|
|
206
217
|
|
|
218
|
+
extern async def mkdir(path: String): Int =
|
|
219
|
+
jsNode "$effekt.capture(callback => mkdir(${path}, callback))"
|
|
220
|
+
llvm """
|
|
221
|
+
call void @c_fs_mkdir(%Pos ${path}, %Stack %stack)
|
|
222
|
+
ret void
|
|
223
|
+
"""
|
|
224
|
+
|
|
207
225
|
def checkResult(result: Int): Int / Exception[IOError] =
|
|
208
226
|
if (result < 0) {
|
|
209
227
|
val ioError = fromNumber(internal::errorNumber(result));
|
|
@@ -29,7 +29,7 @@ def resizableArray[T](): ResizableArray[T] = resizableArray(8)
|
|
|
29
29
|
|
|
30
30
|
/// Throw an OutOfBounds exception if index is not a valid index into arr
|
|
31
31
|
def boundsCheck[T](arr: ResizableArray[T], index: Int): Unit / Exception[OutOfBounds] = {
|
|
32
|
-
if (index < 0
|
|
32
|
+
if (index < 0 || index >= arr.size) {
|
|
33
33
|
do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index))
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -282,7 +282,10 @@ def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[I
|
|
|
282
282
|
push(0, offset)
|
|
283
283
|
return r
|
|
284
284
|
} with emit[Byte] { (byte) =>
|
|
285
|
-
if (offset >= buffer.size) {
|
|
285
|
+
if (offset >= buffer.size) {
|
|
286
|
+
push(0, buffer.size)
|
|
287
|
+
offset = 0
|
|
288
|
+
}
|
|
286
289
|
buffer.unsafeSet(offset, byte)
|
|
287
290
|
offset = offset + 1
|
|
288
291
|
resume(())
|
|
@@ -304,7 +307,6 @@ def readFile[R](path: String) { reader: () => R / read[Byte] }: R / Exception[IO
|
|
|
304
307
|
case 0 =>
|
|
305
308
|
do stop()
|
|
306
309
|
case n =>
|
|
307
|
-
offset = 0
|
|
308
310
|
length = n
|
|
309
311
|
}
|
|
310
312
|
}
|
|
@@ -313,7 +315,10 @@ def readFile[R](path: String) { reader: () => R / read[Byte] }: R / Exception[IO
|
|
|
313
315
|
reader()
|
|
314
316
|
} with read[Byte] {
|
|
315
317
|
resume {
|
|
316
|
-
if (offset >= length) {
|
|
318
|
+
if (offset >= length) {
|
|
319
|
+
pull()
|
|
320
|
+
offset = 0
|
|
321
|
+
}
|
|
317
322
|
val byte = buffer.unsafeGet(offset)
|
|
318
323
|
offset = offset + 1
|
|
319
324
|
return byte
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
package/libraries/llvm/io.c
CHANGED
|
@@ -71,7 +71,7 @@ void c_fs_open(String path, int flags, Stack stack) {
|
|
|
71
71
|
uv_fs_t* request = malloc(sizeof(uv_fs_t));
|
|
72
72
|
request->data = stack;
|
|
73
73
|
|
|
74
|
-
int result = uv_fs_open(uv_default_loop(), request, path_str, flags,
|
|
74
|
+
int result = uv_fs_open(uv_default_loop(), request, path_str, flags, 0777, c_resume_int_fs);
|
|
75
75
|
|
|
76
76
|
if (result < 0) {
|
|
77
77
|
uv_fs_req_cleanup(request);
|
|
@@ -79,7 +79,7 @@ void c_fs_open(String path, int flags, Stack stack) {
|
|
|
79
79
|
resume_Int(stack, result);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
//
|
|
82
|
+
// Free the string since libuv copies it into the request
|
|
83
83
|
free(path_str);
|
|
84
84
|
|
|
85
85
|
return;
|
|
@@ -147,6 +147,29 @@ void c_fs_close(Int file, Stack stack) {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
void c_fs_mkdir(String path, Stack stack) {
|
|
151
|
+
|
|
152
|
+
// Convert the Effekt String to a null-terminated string
|
|
153
|
+
char* path_str = c_bytearray_into_nullterminated_string(path);
|
|
154
|
+
erasePositive((struct Pos) path);
|
|
155
|
+
|
|
156
|
+
uv_fs_t* request = malloc(sizeof(uv_fs_t));
|
|
157
|
+
request->data = stack;
|
|
158
|
+
|
|
159
|
+
// Perform the mkdir operation
|
|
160
|
+
int result = uv_fs_mkdir(uv_default_loop(), request, path_str, 0777, c_resume_int_fs);
|
|
161
|
+
|
|
162
|
+
if (result < 0) {
|
|
163
|
+
uv_fs_req_cleanup(request);
|
|
164
|
+
free(request);
|
|
165
|
+
resume_Int(stack, result);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Free the string since libuv copies it into the request
|
|
169
|
+
free(path_str);
|
|
170
|
+
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
150
173
|
|
|
151
174
|
/**
|
|
152
175
|
* Maps the libuv error code to a stable (platform independent) numeric value.
|