@effekt-lang/effekt 0.18.0 → 0.20.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/buffer.effekt +3 -3
- package/libraries/common/bytearray.effekt +64 -1
- package/libraries/common/effekt.effekt +45 -10
- package/libraries/common/heap.effekt +103 -0
- package/libraries/common/io/filesystem.effekt +49 -66
- package/libraries/common/io/network.effekt +8 -5
- package/libraries/common/json.effekt +30 -22
- package/libraries/common/map.effekt +992 -0
- package/libraries/common/regex.effekt +64 -0
- package/libraries/common/resizable_array.effekt +235 -0
- package/libraries/common/set.effekt +234 -0
- package/libraries/common/stream.effekt +47 -2
- package/libraries/common/string.effekt +7 -0
- package/libraries/common/stringbuffer.effekt +65 -0
- package/libraries/common/union_find.effekt +113 -0
- package/libraries/llvm/bytearray.c +36 -7
- package/libraries/llvm/forward-declare-c.ll +2 -0
- package/libraries/llvm/io.c +17 -43
- package/libraries/llvm/main.c +2 -1
- package/libraries/llvm/panic.c +20 -0
- package/libraries/llvm/rts.ll +141 -142
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
- package/licenses/mit license - mit-license.html +82 -18
- package/licenses/the bsd license - bsd-license.html +81 -17
- package/licenses/the mit license - mit.html +81 -17
- package/package.json +1 -1
- package/libraries/chez/common/text/regex.effekt +0 -31
- package/libraries/js/text/regex.effekt +0 -33
- package/libraries/llvm/hole.c +0 -11
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module stringbuffer
|
|
2
|
+
|
|
3
|
+
import bytearray
|
|
4
|
+
|
|
5
|
+
interface StringBuffer {
|
|
6
|
+
def write(str: String): Unit
|
|
7
|
+
def flush(): String
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
def stringBuffer[A] { prog: => A / StringBuffer }: A = {
|
|
11
|
+
val initialCapacity = 128
|
|
12
|
+
var buffer = bytearray::allocate(initialCapacity)
|
|
13
|
+
// next free index to write to
|
|
14
|
+
var pos = 0
|
|
15
|
+
|
|
16
|
+
def ensureCapacity(sizeToAdd: Int): Unit = {
|
|
17
|
+
val cap = buffer.size - pos + 1
|
|
18
|
+
if (sizeToAdd <= cap) ()
|
|
19
|
+
else {
|
|
20
|
+
// Double the capacity while ensuring the required capacity
|
|
21
|
+
val newSize = max(buffer.size * 2, buffer.size + sizeToAdd)
|
|
22
|
+
buffer = buffer.resize(newSize)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try { prog() }
|
|
27
|
+
with StringBuffer {
|
|
28
|
+
def write(str) = {
|
|
29
|
+
val bytes = fromString(str)
|
|
30
|
+
ensureCapacity(bytes.size)
|
|
31
|
+
bytes.foreach { b =>
|
|
32
|
+
buffer.unsafeSet(pos, b)
|
|
33
|
+
pos = pos + 1
|
|
34
|
+
}
|
|
35
|
+
resume(())
|
|
36
|
+
}
|
|
37
|
+
def flush() = {
|
|
38
|
+
// resize buffer to strip trailing zeros that otherwise would be converted into 0x00 characters
|
|
39
|
+
val str = bytearray::resize(buffer, pos).toString()
|
|
40
|
+
// after flushing, the stringbuffer should be empty again
|
|
41
|
+
buffer = bytearray::allocate(initialCapacity)
|
|
42
|
+
resume(str)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// Handler for string interpolation using a string buffer
|
|
48
|
+
def s { prog: () => Unit / { literal, splice[String] } }: String =
|
|
49
|
+
stringBuffer {
|
|
50
|
+
try { prog(); do flush() }
|
|
51
|
+
with splice[String] { x => resume(do write(x)) }
|
|
52
|
+
with literal { s => resume(do write(s)) }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
namespace examples {
|
|
56
|
+
def main() = {
|
|
57
|
+
with stringBuffer
|
|
58
|
+
do write("hello")
|
|
59
|
+
do write(", world")
|
|
60
|
+
// prints `hello, world`
|
|
61
|
+
println(do flush())
|
|
62
|
+
// prints the empty string
|
|
63
|
+
println(do flush())
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
module union_find
|
|
2
|
+
import resizable_array
|
|
3
|
+
|
|
4
|
+
/// Classic mutable union-find data structure on integer indices,
|
|
5
|
+
/// with union-by-rank and path compression.
|
|
6
|
+
record UnionFind(rawElements: ResizableArray[Int])
|
|
7
|
+
|
|
8
|
+
namespace internal {
|
|
9
|
+
// -(rk + 1) for roots
|
|
10
|
+
// parent for inner nodes
|
|
11
|
+
def isRoot(u: UnionFind, s: Int): Bool / Exception[MissingValue] = {
|
|
12
|
+
with on[OutOfBounds].default { do raise(MissingValue(), "No node " ++ s.show) }
|
|
13
|
+
u.rawElements.get(s) < 0
|
|
14
|
+
}
|
|
15
|
+
def parent(u: UnionFind, s: Int): Int / Exception[MissingValue] = {
|
|
16
|
+
with on[OutOfBounds].default { do raise(MissingValue(), "No node " ++ s.show) }
|
|
17
|
+
val c = u.rawElements.get(s)
|
|
18
|
+
if (c < 0) {
|
|
19
|
+
do raise(MissingValue(), "Root node " ++ s.show ++ " has no parent.")
|
|
20
|
+
} else {
|
|
21
|
+
c
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
def rank(u: UnionFind, s: Int): Int / Exception[MissingValue] = {
|
|
25
|
+
with on[OutOfBounds].default { do raise(MissingValue(), "No node " ++ s.show) }
|
|
26
|
+
val c = u.rawElements.get(s)
|
|
27
|
+
if (c < 0) {
|
|
28
|
+
-1 * c - 1
|
|
29
|
+
} else {
|
|
30
|
+
do raise(MissingValue(), "Only root nodes have a rank.")
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
def setParent(u: UnionFind, child: Int, parent: Int) = {
|
|
34
|
+
with on[OutOfBounds].default { do raise(MissingValue(), "No node " ++ child.show) }
|
|
35
|
+
u.rawElements.set(child, parent)
|
|
36
|
+
}
|
|
37
|
+
def setRank(u: UnionFind, root: Int, rank: Int) = {
|
|
38
|
+
with on[OutOfBounds].default { do raise(MissingValue(), "No node " ++ root.show) }
|
|
39
|
+
u.rawElements.set(root, -1 * rank - 1)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def unionFind(): UnionFind =
|
|
44
|
+
UnionFind(resizableArray())
|
|
45
|
+
|
|
46
|
+
def unionFind(capacity: Int): UnionFind =
|
|
47
|
+
UnionFind(resizableArray(capacity))
|
|
48
|
+
|
|
49
|
+
/// Make a new set in the union-find datastructure and return its index
|
|
50
|
+
///
|
|
51
|
+
/// O(1) amortized, worst-case O(n) if the capacity does not suffice
|
|
52
|
+
def makeSet(u: UnionFind): Int = {
|
|
53
|
+
u.rawElements.add(-1)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// Find the representative of the given element.
|
|
57
|
+
///
|
|
58
|
+
/// O(inverse-ackermann(n)) amortized
|
|
59
|
+
def find(u: UnionFind, s: Int): Int / Exception[MissingValue] = {
|
|
60
|
+
def goFind(s: Int): Int = {
|
|
61
|
+
if (u.internal::isRoot(s)) {
|
|
62
|
+
s
|
|
63
|
+
} else {
|
|
64
|
+
goFind(u.internal::parent(s))
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
val root = goFind(s)
|
|
68
|
+
|
|
69
|
+
def goCompress(s: Int): Unit = {
|
|
70
|
+
if (not(u.internal::isRoot(s))) {
|
|
71
|
+
val p = u.internal::parent(s)
|
|
72
|
+
u.internal::setParent(s, root)
|
|
73
|
+
goCompress(p)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
goCompress(s)
|
|
77
|
+
|
|
78
|
+
root
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Make it such that the sets *represented by* x and y are merged
|
|
82
|
+
///
|
|
83
|
+
/// O(1)
|
|
84
|
+
def unionRoots(u: UnionFind, x: Int, y: Int): Int / Exception[MissingValue] = {
|
|
85
|
+
if(not(u.internal::isRoot(x) && u.internal::isRoot(y))) {
|
|
86
|
+
panic("unionRoots should only be called on representatives")
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
def addChild(root: Int, child: Int) = {
|
|
90
|
+
if (u.internal::rank(root) == u.internal::rank(child)) {
|
|
91
|
+
u.internal::setRank(root, u.internal::rank(root) + 1)
|
|
92
|
+
}
|
|
93
|
+
u.internal::setParent(child, root)
|
|
94
|
+
root
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (x == y) {
|
|
98
|
+
x
|
|
99
|
+
} else if (u.internal::rank(x) < u.internal::rank(y)) {
|
|
100
|
+
addChild(y, x)
|
|
101
|
+
} else {
|
|
102
|
+
addChild(x, y)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// Make it so a and b are in the same set
|
|
107
|
+
///
|
|
108
|
+
/// O(inverse-ackermann(n)) amortized
|
|
109
|
+
def union(u: UnionFind, a: Int, b: Int): Int / Exception[MissingValue] = {
|
|
110
|
+
val x = u.find(a)
|
|
111
|
+
val y = u.find(b)
|
|
112
|
+
u.unionRoots(x, y)
|
|
113
|
+
}
|
|
@@ -152,16 +152,45 @@ struct Pos c_bytearray_equal(const struct Pos left, const struct Pos right) {
|
|
|
152
152
|
erasePositive(right);
|
|
153
153
|
return BooleanFalse;
|
|
154
154
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
|
|
156
|
+
int cmp = memcmp(c_bytearray_data(left), c_bytearray_data(right), left_size);
|
|
157
|
+
erasePositive(left);
|
|
158
|
+
erasePositive(right);
|
|
159
|
+
return (cmp == 0 ? BooleanTrue : BooleanFalse);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
Int c_bytearray_compare(const struct Pos left, const struct Pos right) {
|
|
163
|
+
uint64_t left_size = left.tag;
|
|
164
|
+
uint64_t right_size = right.tag;
|
|
165
|
+
uint64_t min_size = (left_size < right_size) ? left_size : right_size;
|
|
166
|
+
|
|
167
|
+
uint8_t* left_data = c_bytearray_data(left);
|
|
168
|
+
uint8_t* right_data = c_bytearray_data(right);
|
|
169
|
+
|
|
170
|
+
if (left_data == right_data) {
|
|
171
|
+
erasePositive(left);
|
|
172
|
+
erasePositive(right);
|
|
173
|
+
return 0;
|
|
161
174
|
}
|
|
175
|
+
|
|
176
|
+
int cmp = memcmp(left_data, right_data, min_size);
|
|
177
|
+
|
|
162
178
|
erasePositive(left);
|
|
163
179
|
erasePositive(right);
|
|
164
|
-
|
|
180
|
+
|
|
181
|
+
if (cmp < 0) {
|
|
182
|
+
return -1;
|
|
183
|
+
} else if (cmp > 0) {
|
|
184
|
+
return 1;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (left_size < right_size) {
|
|
188
|
+
return -1;
|
|
189
|
+
} else if (left_size > right_size) {
|
|
190
|
+
return 1;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return 0;
|
|
165
194
|
}
|
|
166
195
|
|
|
167
196
|
// TODO deprecate
|
|
@@ -9,6 +9,7 @@ declare void @c_io_println_Double(%Double)
|
|
|
9
9
|
declare void @c_io_println_String(%Pos)
|
|
10
10
|
|
|
11
11
|
declare void @hole()
|
|
12
|
+
declare void @duplicated_prompt()
|
|
12
13
|
|
|
13
14
|
declare %Pos @c_ref_fresh(%Pos)
|
|
14
15
|
declare %Pos @c_ref_get(%Pos)
|
|
@@ -37,6 +38,7 @@ declare %Pos @c_bytearray_show_Double(double)
|
|
|
37
38
|
|
|
38
39
|
declare %Pos @c_bytearray_concatenate(%Pos, %Pos)
|
|
39
40
|
declare %Pos @c_bytearray_equal(%Pos, %Pos)
|
|
41
|
+
declare %Int @c_bytearray_compare(%Pos, %Pos)
|
|
40
42
|
|
|
41
43
|
declare %Pos @c_bytearray_substring(%Pos, i64, i64)
|
|
42
44
|
declare %Int @c_bytearray_character_at(%Pos, i64)
|
package/libraries/llvm/io.c
CHANGED
|
@@ -62,50 +62,12 @@ void c_resume_int_fs(uv_fs_t* request) {
|
|
|
62
62
|
resume_Int(stack, result);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
switch (mode.tag) {
|
|
67
|
-
case 0: // ReadOnly()
|
|
68
|
-
return UV_FS_O_RDONLY;
|
|
69
|
-
case 1: // WriteOnly()
|
|
70
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC;
|
|
71
|
-
case 2: // AppendOnly()
|
|
72
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND;
|
|
73
|
-
case 3: // ReadWrite()
|
|
74
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC;
|
|
75
|
-
case 4: // ReadAppend()
|
|
76
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND;
|
|
77
|
-
case 5: // AppendExclusive()
|
|
78
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_EXCL;
|
|
79
|
-
case 6: // ReadAppendExclusive()
|
|
80
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_EXCL;
|
|
81
|
-
case 7: // AppendSync()
|
|
82
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_SYNC;
|
|
83
|
-
case 8: // ReadAppendSync()
|
|
84
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND | UV_FS_O_SYNC;
|
|
85
|
-
case 9: // ReadSync()
|
|
86
|
-
return UV_FS_O_RDONLY | UV_FS_O_SYNC;
|
|
87
|
-
case 10: // ReadWriteSync()
|
|
88
|
-
return UV_FS_O_RDWR | UV_FS_O_SYNC;
|
|
89
|
-
case 11: // WriteExclusive()
|
|
90
|
-
return UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL;
|
|
91
|
-
case 12: // ReadWriteExclusive()
|
|
92
|
-
return UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL;
|
|
93
|
-
default:
|
|
94
|
-
// Invalid tag value
|
|
95
|
-
return -1;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
void c_fs_open(String path, struct Pos mode, Stack stack) {
|
|
65
|
+
void c_fs_open(String path, int flags, Stack stack) {
|
|
100
66
|
|
|
101
67
|
// Convert the Effekt String to a 0-terminated string
|
|
102
68
|
char* path_str = c_bytearray_into_nullterminated_string(path);
|
|
103
69
|
erasePositive((struct Pos) path);
|
|
104
70
|
|
|
105
|
-
// Convert the Effekt String representing the opening mode to libuv flags
|
|
106
|
-
int flags = modeFlags(mode);
|
|
107
|
-
erasePositive((struct Pos) mode);
|
|
108
|
-
|
|
109
71
|
uv_fs_t* request = malloc(sizeof(uv_fs_t));
|
|
110
72
|
request->data = stack;
|
|
111
73
|
|
|
@@ -123,6 +85,18 @@ void c_fs_open(String path, struct Pos mode, Stack stack) {
|
|
|
123
85
|
return;
|
|
124
86
|
}
|
|
125
87
|
|
|
88
|
+
void c_fs_open_reading(String path, Stack stack) {
|
|
89
|
+
c_fs_open(path, UV_FS_O_RDONLY, stack);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
void c_fs_open_writing(String path, Stack stack) {
|
|
93
|
+
c_fs_open(path, UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC, stack);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
void c_fs_open_appending(String path, Stack stack) {
|
|
97
|
+
c_fs_open(path, UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_APPEND, stack);
|
|
98
|
+
}
|
|
99
|
+
|
|
126
100
|
void c_fs_read(Int file, struct Pos buffer, Int offset, Int size, Int position, Stack stack) {
|
|
127
101
|
|
|
128
102
|
uv_buf_t buf = uv_buf_init((char*)(c_bytearray_data(buffer) + offset), size);
|
|
@@ -177,11 +151,11 @@ void c_fs_close(Int file, Stack stack) {
|
|
|
177
151
|
/**
|
|
178
152
|
* Maps the libuv error code to a stable (platform independent) numeric value.
|
|
179
153
|
*
|
|
180
|
-
* Tries to use most common
|
|
181
|
-
* for those without common
|
|
154
|
+
* Tries to use most common error number integer values, but introduces fresh values (> 200)
|
|
155
|
+
* for those without common error number values.
|
|
182
156
|
*/
|
|
183
|
-
Int c_error_number(Int
|
|
184
|
-
switch (
|
|
157
|
+
Int c_error_number(Int error) {
|
|
158
|
+
switch (error) {
|
|
185
159
|
case UV_EPERM: return 1; // EPERM
|
|
186
160
|
case UV_ENOENT: return 2; // ENOENT
|
|
187
161
|
case UV_ESRCH: return 3; // ESRCH
|
package/libraries/llvm/main.c
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
#include "types.c"
|
|
13
13
|
#include "bytearray.c"
|
|
14
14
|
#include "io.c"
|
|
15
|
-
#include "
|
|
15
|
+
#include "panic.c"
|
|
16
16
|
#include "ref.c"
|
|
17
17
|
#include "array.c"
|
|
18
18
|
|
|
@@ -40,4 +40,5 @@ int main(int argc, char *argv[]) {
|
|
|
40
40
|
uv_loop_t *loop = uv_default_loop();
|
|
41
41
|
uv_run(loop, UV_RUN_DEFAULT);
|
|
42
42
|
uv_loop_close(loop);
|
|
43
|
+
return 0;
|
|
43
44
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#ifndef EFFEKT_PANIC_C
|
|
2
|
+
#define EFFEKT_PANIC_C
|
|
3
|
+
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
|
|
6
|
+
// TODO:
|
|
7
|
+
// this should _morally_ be using `stderr`, but we don't tee it in tests
|
|
8
|
+
// see PR #823 & issue #815 for context
|
|
9
|
+
|
|
10
|
+
void hole() {
|
|
11
|
+
printf("PANIC: Reached a hole in the program\n");
|
|
12
|
+
exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
void duplicated_prompt() {
|
|
16
|
+
printf("PANIC: Continuation invoked itself\n");
|
|
17
|
+
exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#endif
|