@effekt-lang/effekt 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/effekt +0 -0
- package/libraries/common/array.effekt +23 -47
- package/libraries/common/bench.effekt +11 -19
- package/libraries/common/buffer.effekt +8 -20
- package/libraries/common/bytes.effekt +5 -15
- package/libraries/common/dequeue.effekt +5 -5
- package/libraries/common/effekt.effekt +21 -23
- package/libraries/common/io/console.effekt +1 -3
- package/libraries/common/io/error.effekt +20 -28
- package/libraries/common/io/filesystem.effekt +11 -23
- package/libraries/common/list.effekt +333 -333
- package/libraries/common/queue.effekt +1 -3
- package/libraries/common/ref.effekt +7 -17
- package/libraries/common/result.effekt +6 -14
- package/libraries/common/seq.effekt +28 -49
- package/libraries/common/string.effekt +7 -15
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +2 -2
- package/licenses/mit license - mit-license.html +13 -12
- package/licenses/the bsd license - bsd-license.html +12 -13
- package/licenses/the mit license - mit.html +13 -12
- package/package.json +1 -1
package/bin/effekt
CHANGED
|
Binary file
|
|
@@ -4,15 +4,11 @@ import effekt
|
|
|
4
4
|
import exception
|
|
5
5
|
import list
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
* A mutable 0-indexed fixed-sized array.
|
|
9
|
-
*/
|
|
7
|
+
/// A mutable 0-indexed fixed-sized array.
|
|
10
8
|
extern type Array[T]
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* Prefer using `array` constructor instead to ensure that values are defined.
|
|
15
|
-
*/
|
|
10
|
+
/// Allocates a new array of size `size`, keeping its values _undefined_.
|
|
11
|
+
/// Prefer using `array` constructor instead to ensure that values are defined.
|
|
16
12
|
extern global def allocate[T](size: Int): Array[T] =
|
|
17
13
|
js "(new Array(${size}))"
|
|
18
14
|
chez "(make-vector ${size})" // creates an array filled with 0s on CS
|
|
@@ -21,9 +17,7 @@ extern global def allocate[T](size: Int): Array[T] =
|
|
|
21
17
|
ret %Pos %z
|
|
22
18
|
"""
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
* Creates a new Array of size `size` filled with the value `init`
|
|
26
|
-
*/
|
|
20
|
+
/// Creates a new Array of size `size` filled with the value `init`
|
|
27
21
|
def array[T](size: Int, init: T): Array[T] = {
|
|
28
22
|
val arr = allocate[T](size);
|
|
29
23
|
each(0, size) { i =>
|
|
@@ -32,9 +26,7 @@ def array[T](size: Int, init: T): Array[T] = {
|
|
|
32
26
|
arr
|
|
33
27
|
}
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
* Converts a List `list` to an Array
|
|
37
|
-
*/
|
|
29
|
+
/// Converts a List `list` to an Array
|
|
38
30
|
def fromList[T](list: List[T]): Array[T] = {
|
|
39
31
|
val listSize = list.size();
|
|
40
32
|
val arr = allocate(listSize);
|
|
@@ -45,9 +37,7 @@ def fromList[T](list: List[T]): Array[T] = {
|
|
|
45
37
|
return arr;
|
|
46
38
|
}
|
|
47
39
|
|
|
48
|
-
|
|
49
|
-
* Gets the length of the array in constant time.
|
|
50
|
-
*/
|
|
40
|
+
/// Gets the length of the array in constant time.
|
|
51
41
|
extern pure def size[T](arr: Array[T]): Int =
|
|
52
42
|
js "${arr}.length"
|
|
53
43
|
chez "(vector-length ${arr})"
|
|
@@ -56,12 +46,10 @@ extern pure def size[T](arr: Array[T]): Int =
|
|
|
56
46
|
ret %Int %z
|
|
57
47
|
"""
|
|
58
48
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
* Prefer using `get` instead.
|
|
64
|
-
*/
|
|
49
|
+
/// Gets the element of the `arr` at given `index` in constant time.
|
|
50
|
+
/// Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size)
|
|
51
|
+
///
|
|
52
|
+
/// Prefer using `get` instead.
|
|
65
53
|
extern global def unsafeGet[T](arr: Array[T], index: Int): T =
|
|
66
54
|
js "${arr}[${index}]"
|
|
67
55
|
chez "(vector-ref ${arr} ${index})"
|
|
@@ -77,12 +65,10 @@ extern js """
|
|
|
77
65
|
}
|
|
78
66
|
"""
|
|
79
67
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
* Prefer using `set` instead.
|
|
85
|
-
*/
|
|
68
|
+
/// Sets the element of the `arr` at given `index` to `value` in constant time.
|
|
69
|
+
/// Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size)
|
|
70
|
+
///
|
|
71
|
+
/// Prefer using `set` instead.
|
|
86
72
|
extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit =
|
|
87
73
|
js "array$set(${arr}, ${index}, ${value})"
|
|
88
74
|
chez "(begin (vector-set! ${arr} ${index} ${value}) #f)"
|
|
@@ -91,9 +77,7 @@ extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit =
|
|
|
91
77
|
ret %Pos %z
|
|
92
78
|
"""
|
|
93
79
|
|
|
94
|
-
|
|
95
|
-
* Creates a copy of `arr`
|
|
96
|
-
*/
|
|
80
|
+
/// Creates a copy of `arr`
|
|
97
81
|
def copy[T](arr: Array[T]): Array[T] = {
|
|
98
82
|
with on[OutOfBounds].default { <> }; // should not happen
|
|
99
83
|
val len = arr.size;
|
|
@@ -102,10 +86,8 @@ def copy[T](arr: Array[T]): Array[T] = {
|
|
|
102
86
|
newArray
|
|
103
87
|
}
|
|
104
88
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
* starting at `start` (in `from`) and `offset` (in `to`)
|
|
108
|
-
*/
|
|
89
|
+
/// Copies `length`-many elements from `from` to `to`
|
|
90
|
+
/// starting at `start` (in `from`) and `offset` (in `to`)
|
|
109
91
|
def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int): Unit / Exception[OutOfBounds] = {
|
|
110
92
|
val startValid = start >= 0 && start + length <= from.size
|
|
111
93
|
val offsetValid = offset >= 0 && offset + length <= to.size
|
|
@@ -122,26 +104,20 @@ def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int):
|
|
|
122
104
|
|
|
123
105
|
// Derived operations:
|
|
124
106
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
* throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`.
|
|
128
|
-
*/
|
|
107
|
+
/// Gets the element of the `arr` at given `index` in constant time,
|
|
108
|
+
/// throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`.
|
|
129
109
|
def get[T](arr: Array[T], index: Int): T / Exception[OutOfBounds] =
|
|
130
110
|
if (index >= 0 && index < arr.size) arr.unsafeGet(index)
|
|
131
111
|
else do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index))
|
|
132
112
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
* throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`.
|
|
136
|
-
*/
|
|
113
|
+
/// Sets the element of the `arr` at given `index` to `value` in constant time,
|
|
114
|
+
/// throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`.
|
|
137
115
|
def set[T](arr: Array[T], index: Int, value: T): Unit / Exception[OutOfBounds] =
|
|
138
116
|
if (index >= 0 && index < arr.size) unsafeSet(arr, index, value)
|
|
139
117
|
else do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index))
|
|
140
118
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
* and returns a value that will be on that position in the resulting array
|
|
144
|
-
*/
|
|
119
|
+
/// Builds a new Array of size `size` from a computation `index` which gets an index
|
|
120
|
+
/// and returns a value that will be on that position in the resulting array
|
|
145
121
|
def build[T](size: Int) { index: Int => T }: Array[T] = {
|
|
146
122
|
val arr = allocate[T](size);
|
|
147
123
|
each(0, size) { i =>
|
|
@@ -2,13 +2,11 @@ module bench
|
|
|
2
2
|
|
|
3
3
|
type Nanos = Int
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* - chez: Microseconds
|
|
11
|
-
*/
|
|
5
|
+
/// The current time (since UNIX Epoch) in nanoseconds.
|
|
6
|
+
///
|
|
7
|
+
/// The actual precision varies across the different backends.
|
|
8
|
+
/// - js: Milliseconds
|
|
9
|
+
/// - chez: Microseconds
|
|
12
10
|
extern io def timestamp(): Nanos =
|
|
13
11
|
js "Date.now() * 1000000"
|
|
14
12
|
chez "(timestamp)"
|
|
@@ -32,12 +30,10 @@ extern jsNode """
|
|
|
32
30
|
const { performance } = require('node:perf_hooks');
|
|
33
31
|
"""
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
* as gives no guarantees on the absolute time (unlike a UNIX timestamp).
|
|
40
|
-
*/
|
|
33
|
+
/// High-precision timestamp in nanoseconds that should be for measurements.
|
|
34
|
+
///
|
|
35
|
+
/// This timestamp should only be used for **relative** measurements,
|
|
36
|
+
/// as gives no guarantees on the absolute time (unlike a UNIX timestamp).
|
|
41
37
|
extern io def relativeTimestamp(): Nanos =
|
|
42
38
|
js "Math.round(performance.now() * 1000000)"
|
|
43
39
|
default { timestamp() }
|
|
@@ -48,9 +44,7 @@ namespace Duration {
|
|
|
48
44
|
def diff(fromNanos: Nanos, toNanos: Nanos): Duration = toNanos - fromNanos
|
|
49
45
|
}
|
|
50
46
|
|
|
51
|
-
|
|
52
|
-
* Runs the block and returns the time in nanoseconds
|
|
53
|
-
*/
|
|
47
|
+
/// Runs the block and returns the time in nanoseconds
|
|
54
48
|
def timed { block: => Unit }: Duration = {
|
|
55
49
|
val before = relativeTimestamp()
|
|
56
50
|
block()
|
|
@@ -70,9 +64,7 @@ def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit = {
|
|
|
70
64
|
run(iterations, true)
|
|
71
65
|
}
|
|
72
66
|
|
|
73
|
-
|
|
74
|
-
* Takes a duration in nanoseconds and formats it in milliseconds with precision of two decimal digits.
|
|
75
|
-
*/
|
|
67
|
+
/// Takes a duration in nanoseconds and formats it in milliseconds with precision of two decimal digits.
|
|
76
68
|
def formatMs(nanos: Nanos): String = {
|
|
77
69
|
val micros = nanos / 1000000
|
|
78
70
|
val sub = (nanos.mod(1000000).toDouble / 10000.0).round
|
|
@@ -9,34 +9,22 @@ import array
|
|
|
9
9
|
|
|
10
10
|
record BufferOverflow()
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* elements to the head and read from the tail.
|
|
15
|
-
*/
|
|
12
|
+
/// Fixed-size ring buffers (queues) where one can write
|
|
13
|
+
/// elements to the head and read from the tail.
|
|
16
14
|
interface Buffer[T] {
|
|
17
|
-
|
|
18
|
-
* The remaining capacity
|
|
19
|
-
*/
|
|
15
|
+
/// The remaining capacity
|
|
20
16
|
def capacity(): Int
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
* Is this buffer full?
|
|
24
|
-
*/
|
|
18
|
+
/// Is this buffer full?
|
|
25
19
|
def full?(): Bool
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
* Is this buffer empty?
|
|
29
|
-
*/
|
|
21
|
+
/// Is this buffer empty?
|
|
30
22
|
def empty?(): Bool
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
* Read an element from the tail of the buffer
|
|
34
|
-
*/
|
|
24
|
+
/// Read an element from the tail of the buffer
|
|
35
25
|
def read(): Option[T]
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
* Write an element to the head of the buffer
|
|
39
|
-
*/
|
|
27
|
+
/// Write an element to the head of the buffer
|
|
40
28
|
def write(el: T): Unit / Exception[BufferOverflow]
|
|
41
29
|
}
|
|
42
30
|
|
|
@@ -120,4 +108,4 @@ namespace examples {
|
|
|
120
108
|
println(ringbuffer.read());
|
|
121
109
|
println(ringbuffer.read());
|
|
122
110
|
}
|
|
123
|
-
}
|
|
111
|
+
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
module bytes
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* A memory managed, mutable, fixed-length buffer of bytes.
|
|
5
|
-
*/
|
|
3
|
+
/// A memory managed, mutable, fixed-length buffer of bytes.
|
|
6
4
|
extern type Bytes
|
|
7
5
|
// = llvm "%Pos"
|
|
8
6
|
// = js "Uint8Array"
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
* Allocates new bytes with the given `capacity`, setting its values to `0`.
|
|
12
|
-
*/
|
|
8
|
+
/// Allocates new bytes with the given `capacity`, setting its values to `0`.
|
|
13
9
|
extern io def bytes(capacity: Int): Bytes =
|
|
14
10
|
js "(new Uint8Array(${capacity}))"
|
|
15
11
|
llvm """
|
|
@@ -55,9 +51,7 @@ extern io def write(b: Bytes, index: Int, value: Byte): Unit =
|
|
|
55
51
|
ret %Pos zeroinitializer
|
|
56
52
|
"""
|
|
57
53
|
|
|
58
|
-
|
|
59
|
-
* Returns an *aliased* slice of b starting at offset with the given length
|
|
60
|
-
*/
|
|
54
|
+
/// Returns an *aliased* slice of b starting at offset with the given length
|
|
61
55
|
def slice(b: Bytes, offset: Int, length: Int): Bytes = {
|
|
62
56
|
def validOffset() = offset >= 0 && offset < b.size
|
|
63
57
|
def validLength() = length >= 0 && (offset + length) <= b.size
|
|
@@ -66,9 +60,7 @@ def slice(b: Bytes, offset: Int, length: Int): Bytes = {
|
|
|
66
60
|
}
|
|
67
61
|
|
|
68
62
|
|
|
69
|
-
|
|
70
|
-
* Returns a view into the buffer, with the length truncated to n
|
|
71
|
-
*/
|
|
63
|
+
/// Returns a view into the buffer, with the length truncated to n
|
|
72
64
|
def truncated(b: Bytes, n: Int): Bytes =
|
|
73
65
|
b.slice(0, n)
|
|
74
66
|
|
|
@@ -88,9 +80,7 @@ extern pure def toUTF8(b: Bytes): String =
|
|
|
88
80
|
"""
|
|
89
81
|
|
|
90
82
|
namespace unsafe {
|
|
91
|
-
|
|
92
|
-
* Unsafe: offset and length are not checked.
|
|
93
|
-
*/
|
|
83
|
+
/// Unsafe: offset and length are not checked.
|
|
94
84
|
extern io def slice(b: Bytes, offset: Int, length: Int): Bytes =
|
|
95
85
|
js "new Uint8Array(${b}.buffer, ${offset}, ${length})"
|
|
96
86
|
llvm """
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module dequeue
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
/// An implementation of a functional dequeue, using Okasaki's
|
|
5
|
+
/// bankers dequeue implementation.
|
|
6
|
+
///
|
|
7
|
+
/// Translation from the Haskell implementation:
|
|
8
|
+
/// https://hackage.haskell.org/package/dequeue-0.1.12/docs/src/Data-Dequeue.html#Dequeue
|
|
9
9
|
record Dequeue[R](front: List[R], frontSize: Int, rear: List[R], rearSize: Int)
|
|
10
10
|
|
|
11
11
|
def emptyQueue[R](): Dequeue[R] = Dequeue(Nil(), 0, Nil(), 0)
|
|
@@ -144,13 +144,12 @@ extern io def random(): Double =
|
|
|
144
144
|
|
|
145
145
|
// Equality
|
|
146
146
|
// ========
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
*/
|
|
147
|
+
|
|
148
|
+
/// Result of comparison between two objects according to some order:
|
|
149
|
+
///
|
|
150
|
+
/// - `Less()` means that the first object is *before* the first in the order,
|
|
151
|
+
/// - `Equal()` means that the two objects are the same in the order,
|
|
152
|
+
/// - and `Greater()` means that the second object is *before* the first in the order.
|
|
154
153
|
type Ordering {
|
|
155
154
|
Less();
|
|
156
155
|
Equal();
|
|
@@ -160,7 +159,8 @@ type Ordering {
|
|
|
160
159
|
extern pure def genericCompareImpl[R](x: R, y: R): Int =
|
|
161
160
|
js "$effekt.compare(${x}, ${y})"
|
|
162
161
|
|
|
163
|
-
|
|
162
|
+
/// Compares two values of the same type, returning an `Ordering`.
|
|
163
|
+
/// Only available on the JavaScript backend.
|
|
164
164
|
def genericCompare[R](x: R, y: R): Ordering = {
|
|
165
165
|
genericCompareImpl(x, y) match {
|
|
166
166
|
case -1 => Less()
|
|
@@ -182,9 +182,7 @@ def println(o: Ordering): Unit = println(o.show)
|
|
|
182
182
|
// Comparison ops
|
|
183
183
|
// ==============
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
* Structural equality: Not available in the LLVM backend
|
|
187
|
-
*/
|
|
185
|
+
/// Structural equality: Not available in the LLVM backend
|
|
188
186
|
extern pure def equals[R](x: R, y: R): Bool =
|
|
189
187
|
js "$effekt.equals(${x}, ${y})"
|
|
190
188
|
chez "(equal? ${x} ${y})"
|
|
@@ -550,11 +548,19 @@ def infixAnd { first: => Bool } { second: => Bool }: Bool =
|
|
|
550
548
|
|
|
551
549
|
// Bitwise operations
|
|
552
550
|
// ==================
|
|
551
|
+
|
|
552
|
+
/// Arithmetic left shift
|
|
553
553
|
extern pure def bitwiseShl(x: Int, y: Int): Int =
|
|
554
554
|
js "(${x} << ${y})"
|
|
555
555
|
chez "(ash ${x} ${y})"
|
|
556
556
|
llvm "%z = shl %Int ${x}, ${y} ret %Int %z"
|
|
557
557
|
|
|
558
|
+
/// Arithmetic right shift
|
|
559
|
+
extern pure def bitwiseShr(x: Int, y: Int): Int =
|
|
560
|
+
js "(${x} >> ${y})"
|
|
561
|
+
chez "(ash ${x} (- ${y}))"
|
|
562
|
+
llvm "%z = ashr %Int ${x}, ${y} ret %Int %z"
|
|
563
|
+
|
|
558
564
|
extern pure def bitwiseAnd(x: Int, y: Int): Int =
|
|
559
565
|
js "(${x} & ${y})"
|
|
560
566
|
chez "(logand ${x} ${y})"
|
|
@@ -586,16 +592,12 @@ extern pure def toInt(n: Byte): Int =
|
|
|
586
592
|
// chez: #f
|
|
587
593
|
// llvm: null?
|
|
588
594
|
|
|
589
|
-
|
|
590
|
-
* The value used by the FFI to represent undefined values
|
|
591
|
-
*/
|
|
595
|
+
/// The value used by the FFI to represent undefined values
|
|
592
596
|
extern pure def undefined[A](): A =
|
|
593
597
|
js "undefined"
|
|
594
598
|
chez "#f"
|
|
595
599
|
|
|
596
|
-
|
|
597
|
-
* Is an FFI value undefined?
|
|
598
|
-
*/
|
|
600
|
+
/// Is an FFI value undefined?
|
|
599
601
|
extern pure def isUndefined[A](value: A): Bool =
|
|
600
602
|
js "(${value} === undefined || ${value} === null)"
|
|
601
603
|
chez "(eq? ${value} #f)"
|
|
@@ -630,9 +632,7 @@ def loop { f: {Control} => Unit }: Unit = try {
|
|
|
630
632
|
def continue() = loop { f }
|
|
631
633
|
}
|
|
632
634
|
|
|
633
|
-
|
|
634
|
-
* Calls provided action repeatedly. `start` is inclusive, `end` is not.
|
|
635
|
-
*/
|
|
635
|
+
/// Calls provided action repeatedly. `start` is inclusive, `end` is not.
|
|
636
636
|
def each(start: Int, end: Int) { action: (Int) => Unit } = {
|
|
637
637
|
def loop(i: Int): Unit =
|
|
638
638
|
if (i < end) { action(i); loop(i + 1) }
|
|
@@ -640,9 +640,7 @@ def each(start: Int, end: Int) { action: (Int) => Unit } = {
|
|
|
640
640
|
loop(start)
|
|
641
641
|
}
|
|
642
642
|
|
|
643
|
-
|
|
644
|
-
* Calls provided action repeatedly with support for breaking. `start` is inclusive, `end` is not.
|
|
645
|
-
*/
|
|
643
|
+
/// Calls provided action repeatedly with support for breaking. `start` is inclusive, `end` is not.
|
|
646
644
|
def each(start: Int, end: Int) { action: (Int) {Control} => Unit } = {
|
|
647
645
|
var i = start;
|
|
648
646
|
loop { {l} =>
|
|
@@ -7,9 +7,7 @@ interface Console {
|
|
|
7
7
|
def writeLine(content: String): Unit
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
* Handler for the console effect, using the Console available in js
|
|
12
|
-
*/
|
|
10
|
+
/// Handler for the console effect, using the Console available in js
|
|
13
11
|
def console[R] { program: () => R / Console }: R = {
|
|
14
12
|
val c = js::newConsole()
|
|
15
13
|
try {
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
module io/error
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* see: https://docs.libuv.org/en/v1.x/errors.html
|
|
15
|
-
*/
|
|
3
|
+
/// Errors defined by libuv that can occur in IO operations.
|
|
4
|
+
///
|
|
5
|
+
/// In addition to the named error codes, we also assign each error a
|
|
6
|
+
/// (positive) integer value that is stable across the different platforms.
|
|
7
|
+
///
|
|
8
|
+
/// For the mapping of IOError and code values, see function fromCode.
|
|
9
|
+
///
|
|
10
|
+
/// While stable, this integer value is supposed to only be used internally.
|
|
11
|
+
/// All user-facing operations should use values of type IOError, instead.
|
|
12
|
+
///
|
|
13
|
+
/// see: https://docs.libuv.org/en/v1.x/errors.html
|
|
16
14
|
type IOError {
|
|
17
15
|
E2BIG();
|
|
18
16
|
EACCES();
|
|
@@ -97,11 +95,9 @@ type IOError {
|
|
|
97
95
|
EUNATCH()
|
|
98
96
|
}
|
|
99
97
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
* see: https://docs.libuv.org/en/v1.x/errors.html
|
|
104
|
-
*/
|
|
98
|
+
/// Corresponding error message for a libuv error
|
|
99
|
+
///
|
|
100
|
+
/// see: https://docs.libuv.org/en/v1.x/errors.html
|
|
105
101
|
def message(error: IOError): String = error match {
|
|
106
102
|
case E2BIG() => "argument list too long"
|
|
107
103
|
case EACCES() => "permission denied"
|
|
@@ -186,11 +182,9 @@ def message(error: IOError): String = error match {
|
|
|
186
182
|
case EUNATCH() => "protocol driver not attached"
|
|
187
183
|
}
|
|
188
184
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
* see: https://docs.libuv.org/en/v1.x/errors.html
|
|
193
|
-
*/
|
|
185
|
+
/// Corresponding name of a libuv error
|
|
186
|
+
///
|
|
187
|
+
/// see: https://docs.libuv.org/en/v1.x/errors.html
|
|
194
188
|
def name(error: IOError): String = error match {
|
|
195
189
|
case E2BIG() => "E2BIG"
|
|
196
190
|
case EACCES() => "EACCES"
|
|
@@ -275,11 +269,9 @@ def name(error: IOError): String = error match {
|
|
|
275
269
|
case EUNATCH() => "EUNATCH"
|
|
276
270
|
}
|
|
277
271
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
* See documentation of type IOError for further information.
|
|
282
|
-
*/
|
|
272
|
+
/// Translates a integer code value to an IOError.
|
|
273
|
+
///
|
|
274
|
+
/// See documentation of type IOError for further information.
|
|
283
275
|
def fromNumber(number: Int): IOError = number match {
|
|
284
276
|
case 1 => EPERM()
|
|
285
277
|
case 2 => ENOENT()
|
|
@@ -6,10 +6,8 @@ import io
|
|
|
6
6
|
import io/error
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* Backends rely on the order of these
|
|
12
|
-
*/
|
|
9
|
+
/// Represents the file opening modes with their respective flags
|
|
10
|
+
/// Backends rely on the order of these
|
|
13
11
|
type Mode {
|
|
14
12
|
// Most common modes
|
|
15
13
|
ReadOnly() // 'r' exception if does not exist
|
|
@@ -30,15 +28,11 @@ type Mode {
|
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
* A file descriptor. Should not be inspected.
|
|
35
|
-
*/
|
|
31
|
+
/// A file descriptor. Should not be inspected.
|
|
36
32
|
type File = Int
|
|
37
33
|
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
* Reads a file at given path as utf8 encoded string.
|
|
41
|
-
*/
|
|
35
|
+
/// Reads a file at given path as utf8 encoded string.
|
|
42
36
|
def readFile(path: String): String / Exception[IOError] = {
|
|
43
37
|
val fd = open(path, ReadOnly());
|
|
44
38
|
with on[IOError].finalize { close(fd) }
|
|
@@ -71,9 +65,7 @@ def readFile(path: String): String / Exception[IOError] = {
|
|
|
71
65
|
go()
|
|
72
66
|
}
|
|
73
67
|
|
|
74
|
-
|
|
75
|
-
* Writes the (utf8 encoded) string `contents` into the specified file.
|
|
76
|
-
*/
|
|
68
|
+
/// Writes the (utf8 encoded) string `contents` into the specified file.
|
|
77
69
|
def writeFile(path: String, contents: String): Unit / Exception[IOError] = {
|
|
78
70
|
val fd = open(path, WriteOnly());
|
|
79
71
|
with on[IOError].finalize { close(fd) }
|
|
@@ -100,21 +92,17 @@ def writeFile(path: String, contents: String): Unit / Exception[IOError] = {
|
|
|
100
92
|
}
|
|
101
93
|
|
|
102
94
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
* See example below.
|
|
109
|
-
*/
|
|
95
|
+
/// An abstract interface applications can program against.
|
|
96
|
+
///
|
|
97
|
+
/// Can be interpreted with the `filesystem` handler, or virtualized etc.
|
|
98
|
+
///
|
|
99
|
+
/// See example below.
|
|
110
100
|
interface Files {
|
|
111
101
|
def readFile(path: String): String
|
|
112
102
|
def writeFile(path: String, contents: String): Unit
|
|
113
103
|
}
|
|
114
104
|
|
|
115
|
-
|
|
116
|
-
* Using the file system via node.js
|
|
117
|
-
*/
|
|
105
|
+
/// Using the file system via node.js
|
|
118
106
|
def filesystem[R] { program: => R / Files }: R / Exception[IOError] = // TODO move Exception to be bidirectional
|
|
119
107
|
try { program() }
|
|
120
108
|
with Files {
|