@effekt-lang/effekt 0.2.1 → 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/LICENSE +21 -0
- package/README.md +36 -0
- package/bin/effekt +0 -0
- package/bin/effekt.sh +2 -0
- package/libraries/chez/THIRD-PARTY.txt +11 -0
- package/libraries/chez/callcc/datatype.ss +188 -0
- package/libraries/chez/callcc/effekt.ss +31 -0
- package/libraries/chez/callcc/seq.ss +44 -0
- package/libraries/chez/callcc/seq0.ss +69 -0
- package/libraries/chez/callcc/tail.ss +76 -0
- package/libraries/chez/callcc/tail0.ss +89 -0
- package/libraries/chez/common/effekt_primitives.ss +105 -0
- package/libraries/chez/common/immutable/cslist.effekt +37 -0
- package/libraries/chez/common/mutable/dict.effekt +28 -0
- package/libraries/chez/common/text/pregexp.scm +772 -0
- package/libraries/chez/common/text/regex.effekt +31 -0
- package/libraries/chez/lift/effekt.ss +118 -0
- package/libraries/chez/monadic/effekt.ss +84 -0
- package/libraries/chez/monadic/seq0.ss +76 -0
- 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/common/dequeue.effekt +92 -0
- 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/common/list.effekt +687 -0
- 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/common/seq.effekt +914 -0
- package/libraries/common/string.effekt +395 -0
- package/libraries/common/test.effekt +98 -0
- package/libraries/js/effekt_builtins.js +57 -0
- package/libraries/js/effekt_runtime.js +385 -0
- package/libraries/js/io.js +143 -0
- package/libraries/js/mutable/map.effekt +31 -0
- package/libraries/js/text/regex.effekt +33 -0
- package/libraries/js/unsafe/cont.effekt +11 -0
- package/libraries/js/web/dom.effekt +45 -0
- package/libraries/llvm/array.c +53 -0
- package/libraries/llvm/buffer.c +286 -0
- package/libraries/llvm/forward-declare-c.ll +43 -0
- package/libraries/llvm/hole.c +11 -0
- package/libraries/llvm/io.c +566 -0
- package/libraries/llvm/io.ll +19 -0
- package/libraries/llvm/main.c +41 -0
- package/libraries/llvm/ref.c +45 -0
- package/libraries/llvm/rts.ll +761 -0
- package/libraries/llvm/sanity.c +16 -0
- package/libraries/llvm/types.c +43 -0
- package/libraries/ml/effekt.sml +65 -0
- package/libraries/ml/internal/mllist.effekt +9 -0
- package/libraries/ml/internal/mloption.effekt +18 -0
- package/libraries/ml/random.effekt +85 -0
- package/libraries/ml/text/regex.effekt +102 -0
- package/licenses/THIRD-PARTY.txt +21 -0
- package/licenses/apache-2.0 - license-2.0.txt +202 -0
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +61 -0
- package/licenses/kiama-license.txt +373 -0
- package/licenses/kiama-readme.txt +186 -0
- package/licenses/mit license - mit-license.html +1239 -0
- package/licenses/the apache software license, version 2.0 - license-2.0.txt +202 -0
- package/licenses/the bsd license - bsd-license.html +1237 -0
- package/licenses/the mit license - mit.html +1239 -0
- package/package.json +26 -18
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
module buffer
|
|
2
|
+
|
|
3
|
+
import array
|
|
4
|
+
|
|
5
|
+
// TODO (in Effekt compiler)
|
|
6
|
+
// - [ ] fix allocating into actually global region
|
|
7
|
+
// - [ ] fix exceptions on objects
|
|
8
|
+
// - [X] allow omitting braces after `at` for singleton regions
|
|
9
|
+
|
|
10
|
+
record BufferOverflow()
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Fixed-size ring buffers (queues) where one can write
|
|
14
|
+
* elements to the head and read from the tail.
|
|
15
|
+
*/
|
|
16
|
+
interface Buffer[T] {
|
|
17
|
+
/**
|
|
18
|
+
* The remaining capacity
|
|
19
|
+
*/
|
|
20
|
+
def capacity(): Int
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Is this buffer full?
|
|
24
|
+
*/
|
|
25
|
+
def full?(): Bool
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Is this buffer empty?
|
|
29
|
+
*/
|
|
30
|
+
def empty?(): Bool
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Read an element from the tail of the buffer
|
|
34
|
+
*/
|
|
35
|
+
def read(): Option[T]
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Write an element to the head of the buffer
|
|
39
|
+
*/
|
|
40
|
+
def write(el: T): Unit / Exception[BufferOverflow]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def emptyBuffer[T](capacity: Int): Buffer[T] at {global} = {
|
|
44
|
+
if (capacity == 1) refBuffer()
|
|
45
|
+
else arrayBuffer(capacity)
|
|
46
|
+
}
|
|
47
|
+
def arrayBuffer[T](initialCapacity: Int): Buffer[T] at {global} = {
|
|
48
|
+
// TODO allocate buffer (and array) into a region r.
|
|
49
|
+
val contents = emptyArray[T](initialCapacity)
|
|
50
|
+
var head in global = 0
|
|
51
|
+
var tail in global = 0
|
|
52
|
+
|
|
53
|
+
def size(): Int =
|
|
54
|
+
if (tail >= head) { tail - head }
|
|
55
|
+
else { initialCapacity - head + tail }
|
|
56
|
+
|
|
57
|
+
def capacity(): Int = initialCapacity - size()
|
|
58
|
+
|
|
59
|
+
def buffer = new Buffer[T] {
|
|
60
|
+
def capacity() = capacity()
|
|
61
|
+
def full?() = capacity() <= 0
|
|
62
|
+
def empty?() = size() <= 0
|
|
63
|
+
def read() = {
|
|
64
|
+
if (buffer.empty?) None()
|
|
65
|
+
else {
|
|
66
|
+
val result: T = contents.remove(head).getOrElse { <> };
|
|
67
|
+
head = mod(head + 1, initialCapacity)
|
|
68
|
+
Some(result)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
def write(el: T) = {
|
|
72
|
+
if (buffer.full?) <> // raise(BufferOverflow())
|
|
73
|
+
|
|
74
|
+
contents.put(tail, el)
|
|
75
|
+
tail = mod(tail + 1, initialCapacity)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
buffer
|
|
79
|
+
}
|
|
80
|
+
def refBuffer[T](): Buffer[T] at {global} = {
|
|
81
|
+
var content: Option[T] in global = None()
|
|
82
|
+
new Buffer[T] {
|
|
83
|
+
def capacity() = if (content.isEmpty) 1 else 0
|
|
84
|
+
def full?() = content.isDefined
|
|
85
|
+
def empty?() = isEmpty(content)
|
|
86
|
+
def read() = {
|
|
87
|
+
val res = content
|
|
88
|
+
content = None()
|
|
89
|
+
res
|
|
90
|
+
}
|
|
91
|
+
def write(el: T) = content match {
|
|
92
|
+
case Some(v) =>
|
|
93
|
+
<> // do raise(BufferOverflow(), "Cannot read element from buffer")
|
|
94
|
+
case None() =>
|
|
95
|
+
content = Some(el)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
namespace examples {
|
|
101
|
+
def main() = ignore[BufferOverflow] {
|
|
102
|
+
// Buffer with capacity 1
|
|
103
|
+
def b = emptyBuffer[Int](1);
|
|
104
|
+
println(b.capacity);
|
|
105
|
+
println(b.full?);
|
|
106
|
+
|
|
107
|
+
b.write(17);
|
|
108
|
+
println(b.read());
|
|
109
|
+
|
|
110
|
+
// buffer with capacity 3
|
|
111
|
+
def ringbuffer = emptyBuffer[Int](3);
|
|
112
|
+
ringbuffer.write(1);
|
|
113
|
+
ringbuffer.write(2);
|
|
114
|
+
println(ringbuffer.read());
|
|
115
|
+
ringbuffer.write(3);
|
|
116
|
+
println(ringbuffer.read());
|
|
117
|
+
println(ringbuffer.read());
|
|
118
|
+
ringbuffer.write(4);
|
|
119
|
+
ringbuffer.write(5);
|
|
120
|
+
println(ringbuffer.read());
|
|
121
|
+
println(ringbuffer.read());
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
module bytes
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A memory managed, mutable, fixed-length buffer of bytes.
|
|
5
|
+
*/
|
|
6
|
+
extern type Bytes
|
|
7
|
+
// = llvm "%Pos"
|
|
8
|
+
// = js "Uint8Array"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Allocates new bytes with the given `capacity`, setting its values to `0`.
|
|
12
|
+
*/
|
|
13
|
+
extern io def bytes(capacity: Int): Bytes =
|
|
14
|
+
js "(new Uint8Array(${capacity}))"
|
|
15
|
+
llvm """
|
|
16
|
+
%buf = call %Pos @c_buffer_construct_uninitialized(i64 ${capacity})
|
|
17
|
+
ret %Pos %buf
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def copy(b: Bytes): Bytes = {
|
|
21
|
+
val len = b.size
|
|
22
|
+
val clone = bytes(len)
|
|
23
|
+
copy(b, clone, 0, 0, len)
|
|
24
|
+
clone
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
extern io def copy(from: Bytes, to: Bytes, startFrom: Int, startTo: Int, length: Int): Unit =
|
|
28
|
+
js "bytes$copy(${from}, ${to}, ${startFrom}, ${startTo}, ${length})"
|
|
29
|
+
llvm """
|
|
30
|
+
call void @c_buffer_copy(%Pos ${from}, %Pos ${to}, i64 ${startFrom}, i64 ${startTo}, i64 ${length})
|
|
31
|
+
; return Unit
|
|
32
|
+
ret %Pos zeroinitializer
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
extern pure def size(b: Bytes): Int =
|
|
36
|
+
js "${b}.length"
|
|
37
|
+
llvm """
|
|
38
|
+
%size = call i64 @c_buffer_length(%Pos ${b})
|
|
39
|
+
ret i64 %size
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
extern io def read(b: Bytes, index: Int): Byte =
|
|
43
|
+
js "(${b})[${index}]"
|
|
44
|
+
llvm """
|
|
45
|
+
%byte = call i8 @c_buffer_index(%Pos ${b}, i64 ${index})
|
|
46
|
+
ret i8 %byte
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
// TODO should return the number of bytes written.
|
|
50
|
+
extern io def write(b: Bytes, index: Int, value: Byte): Unit =
|
|
51
|
+
js "bytes$set(${b}, ${index}, ${value})"
|
|
52
|
+
llvm """
|
|
53
|
+
call void @c_buffer_set(%Pos ${b}, i64 ${index}, i8 ${value})
|
|
54
|
+
; return Unit
|
|
55
|
+
ret %Pos zeroinitializer
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns an *aliased* slice of b starting at offset with the given length
|
|
60
|
+
*/
|
|
61
|
+
def slice(b: Bytes, offset: Int, length: Int): Bytes = {
|
|
62
|
+
def validOffset() = offset >= 0 && offset < b.size
|
|
63
|
+
def validLength() = length >= 0 && (offset + length) <= b.size
|
|
64
|
+
if (validOffset() && validLength()) unsafe::slice(b, offset, length)
|
|
65
|
+
else panic("Invalid slice of bytes (size: " ++ b.size.show ++ ", offset: " ++ offset.show ++ ", length: " ++ length.show ++ ")")
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns a view into the buffer, with the length truncated to n
|
|
71
|
+
*/
|
|
72
|
+
def truncated(b: Bytes, n: Int): Bytes =
|
|
73
|
+
b.slice(0, n)
|
|
74
|
+
|
|
75
|
+
extern pure def fromUTF8(s: String): Bytes =
|
|
76
|
+
js "(new TextEncoder().encode(${s}))"
|
|
77
|
+
llvm """
|
|
78
|
+
%copy = call %Pos @c_buffer_clone(%Pos ${s})
|
|
79
|
+
ret %Pos %copy
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
extern pure def toUTF8(b: Bytes): String =
|
|
83
|
+
js "(new TextDecoder('utf-8').decode(${b}))"
|
|
84
|
+
// assuming the buffer is already in UTF-8
|
|
85
|
+
llvm """
|
|
86
|
+
%copy = call %Pos @c_buffer_clone(%Pos ${b})
|
|
87
|
+
ret %Pos %copy
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
namespace unsafe {
|
|
91
|
+
/**
|
|
92
|
+
* Unsafe: offset and length are not checked.
|
|
93
|
+
*/
|
|
94
|
+
extern io def slice(b: Bytes, offset: Int, length: Int): Bytes =
|
|
95
|
+
js "new Uint8Array(${b}.buffer, ${offset}, ${length})"
|
|
96
|
+
llvm """
|
|
97
|
+
%buf = call %Pos @c_buffer_slice(%Pos ${b}, i64 ${offset}, i64 ${length})
|
|
98
|
+
ret %Pos %buf
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
extern js """
|
|
105
|
+
function bytes$set(bytes, index, value) {
|
|
106
|
+
bytes[index] = value;
|
|
107
|
+
return $effekt.unit;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function bytes$clone(original) {
|
|
111
|
+
let copy = new Uint8Array(original.length);
|
|
112
|
+
copy.set(original);
|
|
113
|
+
return copy;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function bytes$copy(from, to, startFrom, startTo, length) {
|
|
117
|
+
// Check bounds
|
|
118
|
+
if (startFrom + length > from.length || startTo + length > to.length) {
|
|
119
|
+
throw new RangeError('Index out of bounds');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Create a subarray of 'from' and set it into 'to'
|
|
123
|
+
to.set(from.subarray(startFrom, startFrom + length), startTo);
|
|
124
|
+
}
|
|
125
|
+
"""
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module dequeue
|
|
2
|
+
|
|
3
|
+
|
|
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
|
+
record Dequeue[R](front: List[R], frontSize: Int, rear: List[R], rearSize: Int)
|
|
10
|
+
|
|
11
|
+
def emptyQueue[R](): Dequeue[R] = Dequeue(Nil(), 0, Nil(), 0)
|
|
12
|
+
|
|
13
|
+
def isEmpty[R](dq: Dequeue[R]): Bool = dq match {
|
|
14
|
+
case Dequeue(f, fs, r, rs) => (fs == 0) && (rs == 0)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def size[R](dq: Dequeue[R]): Int = dq match {
|
|
18
|
+
case Dequeue(f, fs, r, rs) => fs + rs
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
def first[R](dq: Dequeue[R]): Option[R] = dq match {
|
|
22
|
+
case Dequeue(f, fs, r, rs) =>
|
|
23
|
+
if ((fs == 0) && (rs == 1)) { r.headOption }
|
|
24
|
+
else { f.headOption }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
def last[R](dq: Dequeue[R]): Option[R] = dq match {
|
|
28
|
+
case Dequeue(f, fs, r, rs) =>
|
|
29
|
+
if ((fs == 1) && (rs == 0)) { f.headOption }
|
|
30
|
+
else { r.headOption }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
def check[R](dq: Dequeue[R]): Dequeue[R] = dq match {
|
|
34
|
+
case Dequeue(f, fs, r, rs) =>
|
|
35
|
+
val c = 4;
|
|
36
|
+
val size1 = (fs + rs) / 2;
|
|
37
|
+
val size2 = (fs + rs) - size1;
|
|
38
|
+
|
|
39
|
+
if (fs > c * rs + 1) {
|
|
40
|
+
val front = f.take(size1);
|
|
41
|
+
val rear = r.append(f.drop(size1).reverse);
|
|
42
|
+
Dequeue(front, size1, rear, size2)
|
|
43
|
+
} else if (rs > c * fs + 1) {
|
|
44
|
+
val front = f.append(r.drop(size1).reverse);
|
|
45
|
+
val rear = r.take(size1);
|
|
46
|
+
Dequeue(front, size2, rear, size1)
|
|
47
|
+
} else {
|
|
48
|
+
dq
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
def pushFront[R](dq: Dequeue[R], el: R): Dequeue[R] = dq match {
|
|
53
|
+
case Dequeue(f, fs, r, rs) => Dequeue(Cons(el, f), fs + 1, r, rs).check
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
def popFront[R](dq: Dequeue[R]): Option[(R, Dequeue[R])] = dq match {
|
|
57
|
+
case Dequeue(Nil(), fs, Cons(x, Nil()), rs) =>
|
|
58
|
+
Some((x, emptyQueue()))
|
|
59
|
+
case Dequeue(Nil(), fs, r, rs) =>
|
|
60
|
+
None()
|
|
61
|
+
case Dequeue(Cons(x, rest), fs, r, rs) =>
|
|
62
|
+
Some((x, Dequeue(rest, fs - 1, r, rs).check))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
def pushBack[R](dq: Dequeue[R], el: R): Dequeue[R] = dq match {
|
|
66
|
+
case Dequeue(f, fs, r, rs) => Dequeue(f, fs, Cons(el, r), rs + 1).check
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
def popBack[R](dq: Dequeue[R]): Option[(R, Dequeue[R])] = dq match {
|
|
70
|
+
case Dequeue(Cons(x, Nil()), fs, Nil(), rs) =>
|
|
71
|
+
Some((x, emptyQueue()))
|
|
72
|
+
case Dequeue(f, fs, Nil(), rs) =>
|
|
73
|
+
None()
|
|
74
|
+
case Dequeue(f, fs, Cons(x, rest), rs) =>
|
|
75
|
+
Some((x, Dequeue(f, fs, rest, rs - 1).check))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def show[A](d: Dequeue[A]) { showA: A => String }: String = {
|
|
80
|
+
val Dequeue(front, frontSize, rear, rearSize) = d;
|
|
81
|
+
"Dequeue(" ++ show(front){showA} ++ ", " ++ show(frontSize) ++ ", " ++
|
|
82
|
+
show(rear){showA} ++ ", " ++ show(rearSize) ++ ")"
|
|
83
|
+
}
|
|
84
|
+
def show(l: Dequeue[Int]): String = show(l) { e => show(e) }
|
|
85
|
+
def show(l: Dequeue[Double]): String = show(l) { e => show(e) }
|
|
86
|
+
def show(l: Dequeue[Bool]): String = show(l) { e => show(e) }
|
|
87
|
+
def show(l: Dequeue[String]): String = show(l) { e => e }
|
|
88
|
+
|
|
89
|
+
def println(l: Dequeue[Int]): Unit = println(show(l))
|
|
90
|
+
def println(l: Dequeue[Double]): Unit = println(show(l))
|
|
91
|
+
def println(l: Dequeue[Bool]): Unit = println(show(l))
|
|
92
|
+
def println(l: Dequeue[String]): Unit = println(show(l))
|