@effekt-lang/effekt 0.5.0 → 0.7.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/bytearray.effekt +71 -0
- package/libraries/common/effekt.effekt +8 -8
- package/libraries/common/io/console.effekt +1 -2
- package/libraries/common/io/filesystem.effekt +46 -62
- package/libraries/common/io/network.effekt +9 -9
- package/libraries/common/io/time.effekt +1 -1
- package/libraries/common/io.effekt +5 -5
- package/libraries/common/ref.effekt +1 -1
- package/libraries/common/string.effekt +3 -14
- package/libraries/js/effekt_builtins.js +5 -1
- package/libraries/js/effekt_runtime.js +185 -352
- package/libraries/llvm/bytearray.c +209 -0
- package/libraries/llvm/forward-declare-c.ll +23 -23
- package/libraries/llvm/io.c +13 -15
- package/libraries/llvm/main.c +3 -3
- package/libraries/llvm/rts.ll +267 -159
- package/libraries/llvm/types.c +3 -2
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +2 -2
- package/package.json +1 -1
- package/libraries/common/bytes.effekt +0 -115
- package/libraries/js/unsafe/cont.effekt +0 -11
- package/libraries/llvm/buffer.c +0 -286
- package/licenses/mit license - mit-license.html +0 -1240
- package/licenses/the bsd license - bsd-license.html +0 -1236
- package/licenses/the mit license - mit.html +0 -1240
package/bin/effekt
CHANGED
|
Binary file
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module bytearray
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A memory managed, mutable, fixed-length array of bytes.
|
|
5
|
+
*/
|
|
6
|
+
extern type ByteArray
|
|
7
|
+
// = llvm "%Pos"
|
|
8
|
+
// = js "Uint8Array"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/// Allocates a new bytearray with the given `size`, its values are undefined.
|
|
12
|
+
extern global def allocate(size: Int): ByteArray =
|
|
13
|
+
js "(new Uint8Array(${size}))"
|
|
14
|
+
llvm """
|
|
15
|
+
%arr = call %Pos @c_bytearray_new(%Int ${size})
|
|
16
|
+
ret %Pos %arr
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
extern pure def size(arr: ByteArray): Int =
|
|
20
|
+
js "${arr}.length"
|
|
21
|
+
llvm """
|
|
22
|
+
%size = call %Int @c_bytearray_size(%Pos ${arr})
|
|
23
|
+
ret %Int %size
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
extern global def unsafeGet(arr: ByteArray, index: Int): Byte =
|
|
27
|
+
js "(${arr})[${index}]"
|
|
28
|
+
llvm """
|
|
29
|
+
%byte = call %Byte @c_bytearray_get(%Pos ${arr}, %Int ${index})
|
|
30
|
+
ret %Byte %byte
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
extern global def unsafeSet(arr: ByteArray, index: Int, value: Byte): Unit =
|
|
34
|
+
js "bytearray$set(${arr}, ${index}, ${value})"
|
|
35
|
+
llvm """
|
|
36
|
+
%z = call %Pos @c_bytearray_set(%Pos ${arr}, %Int ${index}, %Byte ${value})
|
|
37
|
+
ret %Pos %z
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def resize(source: ByteArray, size: Int): ByteArray = {
|
|
41
|
+
val target = allocate(size)
|
|
42
|
+
val n = min(source.size, target.size)
|
|
43
|
+
def go(i: Int): ByteArray =
|
|
44
|
+
if (i < n) {
|
|
45
|
+
target.unsafeSet(i, source.unsafeGet(i))
|
|
46
|
+
go(i + 1)
|
|
47
|
+
} else {
|
|
48
|
+
target
|
|
49
|
+
}
|
|
50
|
+
go(0)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
extern pure def fromUTF8(str: String): ByteArray =
|
|
54
|
+
js "(new TextEncoder().encode(${str}))"
|
|
55
|
+
llvm """
|
|
56
|
+
ret %Pos ${str}
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
extern pure def toUTF8(arr: ByteArray): String =
|
|
60
|
+
js "(new TextDecoder('utf-8').decode(${arr}))"
|
|
61
|
+
// assuming the buffer is already in UTF-8
|
|
62
|
+
llvm """
|
|
63
|
+
ret %Pos ${arr}
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
extern js """
|
|
67
|
+
function bytearray$set(bytes, index, value) {
|
|
68
|
+
bytes[index] = value;
|
|
69
|
+
return $effekt.unit;
|
|
70
|
+
}
|
|
71
|
+
"""
|
|
@@ -56,7 +56,7 @@ extern pure def show(value: Int): String =
|
|
|
56
56
|
js "'' + ${value}"
|
|
57
57
|
chez "(show-number ${value})"
|
|
58
58
|
llvm """
|
|
59
|
-
%z = call %Pos @
|
|
59
|
+
%z = call %Pos @c_bytearray_show_Int(%Int ${value})
|
|
60
60
|
ret %Pos %z
|
|
61
61
|
"""
|
|
62
62
|
|
|
@@ -66,7 +66,7 @@ extern pure def show(value: Double): String =
|
|
|
66
66
|
js "'' + ${value}"
|
|
67
67
|
chez "(show-number ${value})"
|
|
68
68
|
llvm """
|
|
69
|
-
%z = call %Pos @
|
|
69
|
+
%z = call %Pos @c_bytearray_show_Double(%Double ${value})
|
|
70
70
|
ret %Pos %z
|
|
71
71
|
"""
|
|
72
72
|
|
|
@@ -80,13 +80,13 @@ extern pure def show(value: Char): String =
|
|
|
80
80
|
js "String.fromCodePoint(${value})"
|
|
81
81
|
chez "(string (integer->char ${value}))"
|
|
82
82
|
llvm """
|
|
83
|
-
%z = call %Pos @
|
|
83
|
+
%z = call %Pos @c_bytearray_show_Char(%Int ${value})
|
|
84
84
|
ret %Pos %z
|
|
85
85
|
"""
|
|
86
86
|
|
|
87
87
|
extern pure def show(value: Byte): String =
|
|
88
88
|
llvm """
|
|
89
|
-
%z = call %Pos @
|
|
89
|
+
%z = call %Pos @c_bytearray_show_Byte(i8 ${value})
|
|
90
90
|
ret %Pos %z
|
|
91
91
|
"""
|
|
92
92
|
|
|
@@ -105,7 +105,7 @@ extern pure def infixConcat(s1: String, s2: String): String =
|
|
|
105
105
|
js "((${s1}) + (${s2}))"
|
|
106
106
|
chez "(string-append ${s1} ${s2})"
|
|
107
107
|
llvm """
|
|
108
|
-
%spz = call %Pos @
|
|
108
|
+
%spz = call %Pos @c_bytearray_concatenate(%Pos ${s1}, %Pos ${s2})
|
|
109
109
|
ret %Pos %spz
|
|
110
110
|
"""
|
|
111
111
|
|
|
@@ -113,7 +113,7 @@ extern pure def length(str: String): Int =
|
|
|
113
113
|
js "${str}.length"
|
|
114
114
|
chez "(string-length ${str})"
|
|
115
115
|
llvm """
|
|
116
|
-
%x = call %Int @
|
|
116
|
+
%x = call %Int @c_bytearray_size(%Pos ${str})
|
|
117
117
|
call void @erasePositive(%Pos ${str})
|
|
118
118
|
ret %Int %x
|
|
119
119
|
"""
|
|
@@ -122,7 +122,7 @@ extern pure def unsafeSubstring(str: String, from: Int, to: Int): String =
|
|
|
122
122
|
js "${str}.substring(${from}, ${to})"
|
|
123
123
|
chez "(substring ${str} ${from} ${to})" // potentially raises: "Exception in substring: ..."
|
|
124
124
|
llvm """
|
|
125
|
-
%x = call %Pos @
|
|
125
|
+
%x = call %Pos @c_bytearray_substring(%Pos ${str}, i64 ${from}, i64 ${to})
|
|
126
126
|
ret %Pos %x
|
|
127
127
|
"""
|
|
128
128
|
|
|
@@ -239,7 +239,7 @@ extern pure def infixEq(x: String, y: String): Bool =
|
|
|
239
239
|
js "${x} === ${y}"
|
|
240
240
|
chez "(equal? ${x} ${y})"
|
|
241
241
|
llvm """
|
|
242
|
-
%res = call %Pos @
|
|
242
|
+
%res = call %Pos @c_bytearray_equal(%Pos ${x}, %Pos ${y})
|
|
243
243
|
ret %Pos %res
|
|
244
244
|
"""
|
|
245
245
|
|
|
@@ -38,8 +38,7 @@ namespace js {
|
|
|
38
38
|
jsNode "${console}.close()"
|
|
39
39
|
|
|
40
40
|
extern async def readLine(console: JSConsole): String =
|
|
41
|
-
jsNode "$effekt.
|
|
42
|
-
|
|
41
|
+
jsNode "$effekt.capture(k => ${console}.once('line', k))"
|
|
43
42
|
extern io def writeLine(console: JSConsole, message: String): Unit =
|
|
44
43
|
jsNode "${console}.output.write(${message} + '\\n')"
|
|
45
44
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module io/filesystem
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import bytearray
|
|
4
4
|
|
|
5
5
|
import io
|
|
6
6
|
import io/error
|
|
@@ -34,29 +34,21 @@ type File = Int
|
|
|
34
34
|
|
|
35
35
|
/// Reads a file at given path as utf8 encoded string.
|
|
36
36
|
def readFile(path: String): String / Exception[IOError] = {
|
|
37
|
-
val
|
|
38
|
-
with on[IOError].finalize { close(
|
|
37
|
+
val file = open(path, ReadOnly());
|
|
38
|
+
with on[IOError].finalize { close(file) }
|
|
39
39
|
|
|
40
|
-
val
|
|
41
|
-
var
|
|
42
|
-
var
|
|
43
|
-
var offset = 0;
|
|
40
|
+
val chunkSize = 1048576 // 1MB
|
|
41
|
+
var buffer = bytearray::allocate(chunkSize)
|
|
42
|
+
var offset = 0
|
|
44
43
|
|
|
45
44
|
def go(): String = {
|
|
46
|
-
read(
|
|
45
|
+
read(file, buffer, offset, chunkSize, -1) match {
|
|
47
46
|
case 0 =>
|
|
48
|
-
buffer.
|
|
49
|
-
case n and n < 0 => panic("Error!")
|
|
47
|
+
buffer.resize(offset).toUTF8
|
|
50
48
|
case n =>
|
|
51
49
|
offset = offset + n
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (n == readSize && (offset + readSize) > size) {
|
|
55
|
-
val newSize = size * 2
|
|
56
|
-
val newBuffer = bytes(newSize)
|
|
57
|
-
copy(buffer, newBuffer, 0, 0, size)
|
|
58
|
-
buffer = newBuffer
|
|
59
|
-
size = newSize
|
|
50
|
+
if (offset + chunkSize > buffer.size) {
|
|
51
|
+
buffer = buffer.resize(2 * buffer.size)
|
|
60
52
|
}
|
|
61
53
|
go()
|
|
62
54
|
}
|
|
@@ -67,26 +59,18 @@ def readFile(path: String): String / Exception[IOError] = {
|
|
|
67
59
|
|
|
68
60
|
/// Writes the (utf8 encoded) string `contents` into the specified file.
|
|
69
61
|
def writeFile(path: String, contents: String): Unit / Exception[IOError] = {
|
|
70
|
-
val
|
|
71
|
-
with on[IOError].finalize { close(
|
|
62
|
+
val file = open(path, WriteOnly());
|
|
63
|
+
with on[IOError].finalize { close(file) }
|
|
72
64
|
|
|
73
|
-
val
|
|
74
|
-
|
|
75
|
-
// this induces a memcpy that is not strictly necessary, since we use the buffer read-only
|
|
65
|
+
val chunkSize = 1048576 // 1MB
|
|
76
66
|
val buffer = contents.fromUTF8
|
|
77
|
-
val size = buffer.size
|
|
78
|
-
|
|
79
67
|
var offset = 0;
|
|
80
|
-
def remaining() = size - offset
|
|
81
68
|
|
|
82
|
-
def go(): Unit =
|
|
83
|
-
write(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
offset = offset + n;
|
|
88
|
-
if (remaining() > 0) go()
|
|
89
|
-
}
|
|
69
|
+
def go(): Unit = {
|
|
70
|
+
val n = write(file, buffer, offset, min(buffer.size - offset, chunkSize), -1)
|
|
71
|
+
offset = offset + n
|
|
72
|
+
if (offset < buffer.size) { go() }
|
|
73
|
+
}
|
|
90
74
|
|
|
91
75
|
go()
|
|
92
76
|
}
|
|
@@ -114,14 +98,14 @@ def filesystem[R] { program: => R / Files }: R / Exception[IOError] = // TODO mo
|
|
|
114
98
|
def open(path: String, mode: Mode): File / Exception[IOError] =
|
|
115
99
|
internal::checkResult(internal::open(path, mode))
|
|
116
100
|
|
|
117
|
-
def read(
|
|
118
|
-
internal::checkResult(internal::read(
|
|
101
|
+
def read(file: File, buffer: ByteArray, offset: Int, size: Int, position: Int): Int / Exception[IOError] =
|
|
102
|
+
internal::checkResult(internal::read(file, buffer, offset, size, position))
|
|
119
103
|
|
|
120
|
-
def write(
|
|
121
|
-
internal::checkResult(internal::write(
|
|
104
|
+
def write(file: File, buffer: ByteArray, offset: Int, size: Int, position: Int): Int / Exception[IOError] =
|
|
105
|
+
internal::checkResult(internal::write(file, buffer, offset, size, position))
|
|
122
106
|
|
|
123
|
-
def close(
|
|
124
|
-
internal::checkResult(internal::close(
|
|
107
|
+
def close(file: File): Unit / Exception[IOError] = {
|
|
108
|
+
internal::checkResult(internal::close(file)); ()
|
|
125
109
|
}
|
|
126
110
|
|
|
127
111
|
namespace internal {
|
|
@@ -174,27 +158,27 @@ namespace internal {
|
|
|
174
158
|
const fs = require("fs");
|
|
175
159
|
|
|
176
160
|
function open(path, mode, callback) {
|
|
177
|
-
fs.open(path, modeName(mode), (err,
|
|
178
|
-
if (err) { callback(err.errno) } else { callback(
|
|
161
|
+
fs.open(path, modeName(mode), (err, file) => {
|
|
162
|
+
if (err) { callback(err.errno) } else { callback(file) }
|
|
179
163
|
})
|
|
180
164
|
}
|
|
181
165
|
|
|
182
|
-
function read(
|
|
183
|
-
let
|
|
184
|
-
fs.read(
|
|
166
|
+
function read(file, buffer, offset, size, position, callback) {
|
|
167
|
+
let positionOrNull = position === -1 ? null : position;
|
|
168
|
+
fs.read(file, toBuffer(buffer), offset, size, positionOrNull, (err, bytesRead) => {
|
|
185
169
|
if (err) { callback(err.errno) } else { callback(bytesRead) }
|
|
186
170
|
})
|
|
187
171
|
}
|
|
188
172
|
|
|
189
|
-
function write(
|
|
190
|
-
let
|
|
191
|
-
fs.write(
|
|
173
|
+
function write(file, buffer, offset, size, position, callback) {
|
|
174
|
+
let positionOrNull = position === -1 ? null : position;
|
|
175
|
+
fs.write(file, toBuffer(buffer), offset, size, positionOrNull, (err, bytesWritten) => {
|
|
192
176
|
if (err) { callback(err.errno) } else { callback(bytesWritten) }
|
|
193
177
|
})
|
|
194
178
|
}
|
|
195
179
|
|
|
196
|
-
function close(
|
|
197
|
-
fs.close(
|
|
180
|
+
function close(file, callback) {
|
|
181
|
+
fs.close(file, (err) => {
|
|
198
182
|
if (err) { callback(err.errno) } else { callback(0) }
|
|
199
183
|
})
|
|
200
184
|
}
|
|
@@ -202,36 +186,36 @@ namespace internal {
|
|
|
202
186
|
|
|
203
187
|
extern llvm """
|
|
204
188
|
declare void @c_fs_open(%Pos, %Pos, %Stack)
|
|
205
|
-
declare void @c_fs_read(%Int, %Pos, %Int, %Stack)
|
|
206
|
-
declare void @c_fs_write(%Int, %Pos, %Int, %Stack)
|
|
189
|
+
declare void @c_fs_read(%Int, %Pos, %Int, %Int, %Int, %Stack)
|
|
190
|
+
declare void @c_fs_write(%Int, %Pos, %Int, %Int, %Int, %Stack)
|
|
207
191
|
declare void @c_fs_close(%Int, %Stack)
|
|
208
192
|
"""
|
|
209
193
|
|
|
210
194
|
extern async def open(path: String, mode: Mode): Int =
|
|
211
|
-
jsNode "$effekt.
|
|
195
|
+
jsNode "$effekt.capture(callback => open(${path}, ${mode}, callback))"
|
|
212
196
|
llvm """
|
|
213
197
|
call void @c_fs_open(%Pos ${path}, %Pos ${mode}, %Stack %stack)
|
|
214
198
|
ret void
|
|
215
199
|
"""
|
|
216
200
|
|
|
217
|
-
extern async def read(
|
|
218
|
-
jsNode "$effekt.
|
|
201
|
+
extern async def read(file: Int, buffer: ByteArray, offset: Int, size: Int, position: Int): Int =
|
|
202
|
+
jsNode "$effekt.capture(callback => read(${file}, ${buffer}, ${offset}, ${size}, ${position}, callback))"
|
|
219
203
|
llvm """
|
|
220
|
-
call void @c_fs_read(%Int ${
|
|
204
|
+
call void @c_fs_read(%Int ${file}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Int ${position}, %Stack %stack)
|
|
221
205
|
ret void
|
|
222
206
|
"""
|
|
223
207
|
|
|
224
|
-
extern async def write(
|
|
225
|
-
jsNode "$effekt.
|
|
208
|
+
extern async def write(file: Int, buffer: ByteArray, offset: Int, size: Int, position: Int): Int =
|
|
209
|
+
jsNode "$effekt.capture(callback => write(${file}, ${buffer}, ${offset}, ${size}, ${position}, callback))"
|
|
226
210
|
llvm """
|
|
227
|
-
call void @c_fs_write(%Int ${
|
|
211
|
+
call void @c_fs_write(%Int ${file}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Int ${position}, %Stack %stack)
|
|
228
212
|
ret void
|
|
229
213
|
"""
|
|
230
214
|
|
|
231
|
-
extern async def close(
|
|
232
|
-
jsNode "$effekt.
|
|
215
|
+
extern async def close(file: Int): Int =
|
|
216
|
+
jsNode "$effekt.capture(callback => close(${file}, callback))"
|
|
233
217
|
llvm """
|
|
234
|
-
call void @c_fs_close(%Int ${
|
|
218
|
+
call void @c_fs_close(%Int ${file}, %Stack %stack)
|
|
235
219
|
ret void
|
|
236
220
|
"""
|
|
237
221
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module io/network
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import bytearray
|
|
4
4
|
import io
|
|
5
5
|
|
|
6
6
|
namespace js {
|
|
@@ -18,21 +18,21 @@ namespace js {
|
|
|
18
18
|
extern io def server(): JSServer =
|
|
19
19
|
jsNode "net.createServer()"
|
|
20
20
|
extern io def listen(server: JSServer, port: Int, host: String, listener: JSSocket => Unit at {io, async, global}): Unit =
|
|
21
|
-
jsNode "listen(${server}, ${port}, ${host}, (socket) => (${listener})(socket)
|
|
21
|
+
jsNode "listen(${server}, ${port}, ${host}, (socket) => $effekt.runToplevel((ks, k) => (${listener})(socket, ks, k)))"
|
|
22
22
|
|
|
23
|
-
extern async def send(socket: JSSocket, data:
|
|
24
|
-
jsNode "$effekt.
|
|
23
|
+
extern async def send(socket: JSSocket, data: ByteArray): Unit =
|
|
24
|
+
jsNode "$effekt.capture(callback => ${socket}.write(${data}, callback))"
|
|
25
25
|
|
|
26
|
-
extern async def receive(socket: JSSocket):
|
|
27
|
-
jsNode "$effekt.
|
|
26
|
+
extern async def receive(socket: JSSocket): ByteArray =
|
|
27
|
+
jsNode "$effekt.capture(callback => ${socket}.once('data', callback))"
|
|
28
28
|
|
|
29
29
|
extern async def end(socket: JSSocket): Unit =
|
|
30
|
-
jsNode "$effekt.
|
|
30
|
+
jsNode "$effekt.capture(k => ${socket}.end(k))"
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
interface Socket {
|
|
34
|
-
def send(message:
|
|
35
|
-
def receive():
|
|
34
|
+
def send(message: ByteArray): Unit
|
|
35
|
+
def receive(): ByteArray
|
|
36
36
|
def end(): Unit
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -5,7 +5,7 @@ extern llvm """
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
extern async def wait(millis: Int): Unit =
|
|
8
|
-
js "$effekt.
|
|
8
|
+
js "$effekt.capture(k => setTimeout(() => k($effekt.unit), ${millis}))"
|
|
9
9
|
llvm """
|
|
10
10
|
call void @c_timer_start(%Int ${millis}, %Stack %stack)
|
|
11
11
|
ret void
|
|
@@ -13,7 +13,7 @@ extern llvm """
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
extern async def spawn(task: Task[Unit]): Unit =
|
|
16
|
-
js "$effekt.
|
|
16
|
+
js "$effekt.capture(k => { setTimeout(() => k($effekt.unit), 0); return $effekt.run(${task}) })"
|
|
17
17
|
llvm """
|
|
18
18
|
call void @c_yield(%Stack %stack)
|
|
19
19
|
call void @run(%Neg ${task})
|
|
@@ -21,14 +21,14 @@ extern async def spawn(task: Task[Unit]): Unit =
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
extern async def yield(): Unit =
|
|
24
|
-
js "$effekt.
|
|
24
|
+
js "$effekt.capture(k => setTimeout(() => k($effekt.unit), 0))"
|
|
25
25
|
llvm """
|
|
26
26
|
call void @c_yield(%Stack %stack)
|
|
27
27
|
ret void
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
30
|
extern async def abort(): Nothing =
|
|
31
|
-
js "$effekt.
|
|
31
|
+
js "$effekt.capture(k => undefined)"
|
|
32
32
|
llvm """
|
|
33
33
|
call void @eraseStack(%Stack %stack)
|
|
34
34
|
ret void
|
|
@@ -55,14 +55,14 @@ extern llvm """
|
|
|
55
55
|
"""
|
|
56
56
|
|
|
57
57
|
extern async def await[T](promise: Promise[T]): T =
|
|
58
|
-
js "$effekt.
|
|
58
|
+
js "$effekt.capture(k => ${promise}.promise.then(k))"
|
|
59
59
|
llvm """
|
|
60
60
|
call void @c_promise_await(%Pos ${promise}, %Stack %stack)
|
|
61
61
|
ret void
|
|
62
62
|
"""
|
|
63
63
|
|
|
64
64
|
extern async def resolve[T](promise: Promise[T], value: T): Unit =
|
|
65
|
-
js "$effekt.
|
|
65
|
+
js "$effekt.capture(k => { ${promise}.resolve(${value}); return k($effekt.unit) })"
|
|
66
66
|
llvm """
|
|
67
67
|
call void @c_promise_resolve(%Pos ${promise}, %Pos ${value}, %Stack %stack)
|
|
68
68
|
ret void
|
|
@@ -12,7 +12,7 @@ extern js """
|
|
|
12
12
|
/// Global, mutable references
|
|
13
13
|
extern type Ref[T]
|
|
14
14
|
|
|
15
|
-
/// Allocates a new reference
|
|
15
|
+
/// Allocates a new reference, keeping its value _undefined_.
|
|
16
16
|
/// Prefer using `ref` constructor instead to ensure that the value is defined.
|
|
17
17
|
extern global def allocate[T](): Ref[T] =
|
|
18
18
|
js "{ value: undefined }"
|
|
@@ -14,7 +14,6 @@ import result
|
|
|
14
14
|
/**
|
|
15
15
|
* Strings
|
|
16
16
|
* - JS: Strings are represented as UTF-16 code units where some characters take 2 slots (surrogate pairs)
|
|
17
|
-
* - ML: Strings are sequences of 8-bit characters (https://smlfamily.github.io/Basis/string.html)
|
|
18
17
|
* - Chez: Strings are sequences of unicode characters (?)
|
|
19
18
|
* - LLVM: UTF-8 (characters can take from 1-4 bytes).
|
|
20
19
|
*/
|
|
@@ -237,14 +236,14 @@ def printing[T] { prog: => T / Stream }: T = <>
|
|
|
237
236
|
// ----------
|
|
238
237
|
//
|
|
239
238
|
// JS: Int (Unicode codepoints)
|
|
240
|
-
//
|
|
239
|
+
// Chez: ?
|
|
241
240
|
// LLVM: i64 representing utf-8 (varying length 1-4 bytes)
|
|
242
241
|
|
|
243
242
|
extern pure def toString(ch: Char): String =
|
|
244
243
|
js "String.fromCodePoint(${ch})"
|
|
245
244
|
chez "(string (integer->char ${ch}))"
|
|
246
245
|
llvm """
|
|
247
|
-
%z = call %Pos @
|
|
246
|
+
%z = call %Pos @c_bytearray_show_Char(%Int ${ch})
|
|
248
247
|
ret %Pos %z
|
|
249
248
|
"""
|
|
250
249
|
|
|
@@ -324,16 +323,6 @@ def utf16UnitCount(codepoint: Char): Int = codepoint match {
|
|
|
324
323
|
case c => panic("Not a valid code point")
|
|
325
324
|
}
|
|
326
325
|
|
|
327
|
-
// TODO this is copied from the LLVM-backend stdlib. Do we need this?
|
|
328
|
-
// def showQuoted(s: String): String =
|
|
329
|
-
// "\x22" ++ s.map { c =>
|
|
330
|
-
// if(c == "\x22") {
|
|
331
|
-
// "\\\x22"
|
|
332
|
-
// } else if (c == "\\") {
|
|
333
|
-
// "\\\\"
|
|
334
|
-
// } else c
|
|
335
|
-
// } ++ "\x22"
|
|
336
|
-
|
|
337
326
|
extern pure def charWidth(c: Char): Int =
|
|
338
327
|
// JavaScript strings are UTF-16 where every unicode character after 0xffff takes two units
|
|
339
328
|
js "(${c} > 0xffff) ? 2 : 1"
|
|
@@ -348,6 +337,6 @@ extern pure def unsafeCharAt(str: String, n: Int): Char =
|
|
|
348
337
|
js "${str}.codePointAt(${n})"
|
|
349
338
|
chez "(char->integer (string-ref ${str} ${n}))"
|
|
350
339
|
llvm """
|
|
351
|
-
%x = call %Int @
|
|
340
|
+
%x = call %Int @c_bytearray_character_at(%Pos ${str}, %Int ${n})
|
|
352
341
|
ret %Int %x
|
|
353
342
|
"""
|
|
@@ -54,4 +54,8 @@ $effekt.println = function println$impl(str) {
|
|
|
54
54
|
console.log(str); return $effekt.unit;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
$effekt.unit = { __unit: true }
|
|
57
|
+
$effekt.unit = { __unit: true }
|
|
58
|
+
|
|
59
|
+
$effekt.emptyMatch = function() { throw "empty match" }
|
|
60
|
+
|
|
61
|
+
$effekt.hole = function() { throw "not implemented, yet" }
|