@effekt-lang/effekt 0.18.0 → 0.19.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 +23 -10
- 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/set.effekt +234 -0
- package/libraries/common/stream.effekt +45 -0
- package/libraries/common/string.effekt +7 -0
- package/libraries/llvm/bytearray.c +36 -7
- package/libraries/llvm/forward-declare-c.ll +1 -0
- package/libraries/llvm/main.c +1 -0
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +2 -2
- package/licenses/mit license - mit-license.html +15 -11
- package/licenses/the bsd license - bsd-license.html +16 -12
- package/licenses/the mit license - mit.html +15 -11
- package/package.json +1 -1
- package/libraries/chez/common/text/regex.effekt +0 -31
- package/libraries/js/text/regex.effekt +0 -33
package/bin/effekt
CHANGED
|
Binary file
|
|
@@ -34,7 +34,7 @@ def emptyBuffer[T](capacity: Int): Buffer[T] at {global} = {
|
|
|
34
34
|
}
|
|
35
35
|
def arrayBuffer[T](initialCapacity: Int): Buffer[T] at {global} = {
|
|
36
36
|
// TODO allocate buffer (and array) into a region r.
|
|
37
|
-
val contents =
|
|
37
|
+
val contents = array::allocate[T](initialCapacity)
|
|
38
38
|
var head in global = 0
|
|
39
39
|
var tail in global = 0
|
|
40
40
|
|
|
@@ -51,7 +51,7 @@ def arrayBuffer[T](initialCapacity: Int): Buffer[T] at {global} = {
|
|
|
51
51
|
def read() = {
|
|
52
52
|
if (buffer.empty?) None()
|
|
53
53
|
else {
|
|
54
|
-
val result: T = contents.
|
|
54
|
+
val result: T = contents.unsafeGet(head);
|
|
55
55
|
head = mod(head + 1, initialCapacity)
|
|
56
56
|
Some(result)
|
|
57
57
|
}
|
|
@@ -59,7 +59,7 @@ def arrayBuffer[T](initialCapacity: Int): Buffer[T] at {global} = {
|
|
|
59
59
|
def write(el: T) = {
|
|
60
60
|
if (buffer.full?) <> // raise(BufferOverflow())
|
|
61
61
|
|
|
62
|
-
contents.
|
|
62
|
+
contents.unsafeSet(tail, el)
|
|
63
63
|
tail = mod(tail + 1, initialCapacity)
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -6,7 +6,7 @@ module bytearray
|
|
|
6
6
|
extern type ByteArray
|
|
7
7
|
// = llvm "%Pos"
|
|
8
8
|
// = js "Uint8Array"
|
|
9
|
-
|
|
9
|
+
// = chez "bytevector"
|
|
10
10
|
|
|
11
11
|
/// Allocates a new bytearray with the given `size`, its values are undefined.
|
|
12
12
|
extern global def allocate(size: Int): ByteArray =
|
|
@@ -15,6 +15,7 @@ extern global def allocate(size: Int): ByteArray =
|
|
|
15
15
|
%arr = call %Pos @c_bytearray_new(%Int ${size})
|
|
16
16
|
ret %Pos %arr
|
|
17
17
|
"""
|
|
18
|
+
chez "(make-bytevector ${size})"
|
|
18
19
|
|
|
19
20
|
extern pure def size(arr: ByteArray): Int =
|
|
20
21
|
js "${arr}.length"
|
|
@@ -22,6 +23,7 @@ extern pure def size(arr: ByteArray): Int =
|
|
|
22
23
|
%size = call %Int @c_bytearray_size(%Pos ${arr})
|
|
23
24
|
ret %Int %size
|
|
24
25
|
"""
|
|
26
|
+
chez "(bytevector-length ${arr})"
|
|
25
27
|
|
|
26
28
|
extern global def unsafeGet(arr: ByteArray, index: Int): Byte =
|
|
27
29
|
js "(${arr})[${index}]"
|
|
@@ -29,6 +31,7 @@ extern global def unsafeGet(arr: ByteArray, index: Int): Byte =
|
|
|
29
31
|
%byte = call %Byte @c_bytearray_get(%Pos ${arr}, %Int ${index})
|
|
30
32
|
ret %Byte %byte
|
|
31
33
|
"""
|
|
34
|
+
chez "(bytevector-u8-ref ${arr} ${index})"
|
|
32
35
|
|
|
33
36
|
extern global def unsafeSet(arr: ByteArray, index: Int, value: Byte): Unit =
|
|
34
37
|
js "bytearray$set(${arr}, ${index}, ${value})"
|
|
@@ -36,6 +39,7 @@ extern global def unsafeSet(arr: ByteArray, index: Int, value: Byte): Unit =
|
|
|
36
39
|
%z = call %Pos @c_bytearray_set(%Pos ${arr}, %Int ${index}, %Byte ${value})
|
|
37
40
|
ret %Pos %z
|
|
38
41
|
"""
|
|
42
|
+
chez "(bytevector-u8-set! ${arr} ${index} ${value})"
|
|
39
43
|
|
|
40
44
|
def resize(source: ByteArray, size: Int): ByteArray = {
|
|
41
45
|
val target = allocate(size)
|
|
@@ -75,6 +79,7 @@ extern pure def fromString(str: String): ByteArray =
|
|
|
75
79
|
llvm """
|
|
76
80
|
ret %Pos ${str}
|
|
77
81
|
"""
|
|
82
|
+
chez "(string->utf8 ${str})"
|
|
78
83
|
|
|
79
84
|
extern pure def toString(arr: ByteArray): String =
|
|
80
85
|
js "(new TextDecoder('utf-8').decode(${arr}))"
|
|
@@ -82,10 +87,68 @@ extern pure def toString(arr: ByteArray): String =
|
|
|
82
87
|
llvm """
|
|
83
88
|
ret %Pos ${arr}
|
|
84
89
|
"""
|
|
90
|
+
chez "(utf8->string ${arr})"
|
|
85
91
|
|
|
86
92
|
extern js """
|
|
87
93
|
function bytearray$set(bytes, index, value) {
|
|
88
94
|
bytes[index] = value;
|
|
89
95
|
return $effekt.unit;
|
|
90
96
|
}
|
|
97
|
+
|
|
98
|
+
function bytearray$compare(arr1, arr2) {
|
|
99
|
+
const len = Math.min(arr1.length, arr2.length);
|
|
100
|
+
|
|
101
|
+
for (let i = 0; i < len; i++) {
|
|
102
|
+
if (arr1[i] !== arr2[i]) {
|
|
103
|
+
return arr1[i] < arr2[i] ? -1 : 1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (arr1.length !== arr2.length) {
|
|
108
|
+
return arr1.length < arr2.length ? -1 : 1;
|
|
109
|
+
} else {
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
extern chez """
|
|
116
|
+
(define (bytearray$compare b1 b2)
|
|
117
|
+
(let ([len1 (bytevector-length b1)]
|
|
118
|
+
[len2 (bytevector-length b2)]
|
|
119
|
+
[minlen (min (bytevector-length b1) (bytevector-length b2))])
|
|
120
|
+
(let loop ([i 0])
|
|
121
|
+
(cond
|
|
122
|
+
[(= i minlen)
|
|
123
|
+
(cond [(< len1 len2) -1]
|
|
124
|
+
[(> len1 len2) 1]
|
|
125
|
+
[else 0])]
|
|
126
|
+
[(< (bytevector-u8-ref b1 i) (bytevector-u8-ref b2 i)) -1]
|
|
127
|
+
[(> (bytevector-u8-ref b1 i) (bytevector-u8-ref b2 i)) 1]
|
|
128
|
+
[else (loop (+ i 1))]))))
|
|
91
129
|
"""
|
|
130
|
+
|
|
131
|
+
extern pure def compareByteArrayImpl(b1: ByteArray, b2: ByteArray): Int =
|
|
132
|
+
js "bytearray$compare(${b1}, ${b2})"
|
|
133
|
+
llvm """
|
|
134
|
+
%x = call %Int @c_bytearray_compare(%Pos ${b1}, %Pos ${b2})
|
|
135
|
+
ret %Int %x
|
|
136
|
+
"""
|
|
137
|
+
chez "(bytearray$compare ${b1} ${b2})"
|
|
138
|
+
|
|
139
|
+
def compareByteArray(b1: ByteArray, b2: ByteArray): Ordering = {
|
|
140
|
+
val ret = compareByteArrayImpl(b1, b2)
|
|
141
|
+
if (ret == 0) {
|
|
142
|
+
Equal()
|
|
143
|
+
} else if (ret < 0) {
|
|
144
|
+
Less()
|
|
145
|
+
} else { // ret > 0
|
|
146
|
+
Greater()
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
def compareStringBytes(left: String, right: String): Ordering = {
|
|
151
|
+
val l = left.fromString
|
|
152
|
+
val r = right.fromString
|
|
153
|
+
compareByteArray(l, r)
|
|
154
|
+
}
|
|
@@ -90,6 +90,7 @@ extern pure def show(value: Char): String =
|
|
|
90
90
|
|
|
91
91
|
extern pure def show(value: Byte): String =
|
|
92
92
|
js "'' + ${value}"
|
|
93
|
+
chez "(string ${value})"
|
|
93
94
|
llvm """
|
|
94
95
|
%z = call %Pos @c_bytearray_show_Byte(i8 ${value})
|
|
95
96
|
ret %Pos %z
|
|
@@ -166,17 +167,24 @@ type Ordering {
|
|
|
166
167
|
Greater()
|
|
167
168
|
}
|
|
168
169
|
|
|
170
|
+
def compareInt(n: Int, m: Int) =
|
|
171
|
+
if (n == m) Equal()
|
|
172
|
+
else if (n < m) Less()
|
|
173
|
+
else Greater()
|
|
174
|
+
|
|
169
175
|
extern pure def genericCompareImpl[R](x: R, y: R): Int =
|
|
170
176
|
js "$effekt.compare(${x}, ${y})"
|
|
171
177
|
|
|
172
178
|
/// Compares two values of the same type, returning an `Ordering`.
|
|
173
179
|
/// Only available on the JavaScript backend.
|
|
174
180
|
def genericCompare[R](x: R, y: R): Ordering = {
|
|
175
|
-
genericCompareImpl(x, y)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
181
|
+
val ret = genericCompareImpl(x, y)
|
|
182
|
+
if (ret == 0) {
|
|
183
|
+
Equal()
|
|
184
|
+
} else if (ret < 0) {
|
|
185
|
+
Less()
|
|
186
|
+
} else { // ret > 0
|
|
187
|
+
Greater()
|
|
180
188
|
}
|
|
181
189
|
}
|
|
182
190
|
|
|
@@ -390,7 +398,7 @@ extern pure def log(x: Double): Double =
|
|
|
390
398
|
extern pure def log1p(x: Double): Double =
|
|
391
399
|
js "Math.log1p(${x})"
|
|
392
400
|
chez "(log (+ ${x} 1))"
|
|
393
|
-
llvm "%z = call %Double @log1p(double ${x}) ret %Double %z"
|
|
401
|
+
llvm "%z = call %Double @log1p(double ${x}) ret %Double %z"
|
|
394
402
|
|
|
395
403
|
extern pure def exp(x: Double): Double =
|
|
396
404
|
js "Math.exp(${x})"
|
|
@@ -571,19 +579,19 @@ extern pure def infixGte(x: Double, y: Double): Bool =
|
|
|
571
579
|
// TODO do we really need those? if yes, move to string.effekt
|
|
572
580
|
extern pure def infixLt(x: String, y: String): Bool =
|
|
573
581
|
js "(${x} < ${y})"
|
|
574
|
-
chez "(
|
|
582
|
+
chez "(string<? ${x} ${y})"
|
|
575
583
|
|
|
576
584
|
extern pure def infixLte(x: String, y: String): Bool =
|
|
577
585
|
js "(${x} <= ${y})"
|
|
578
|
-
chez "(
|
|
586
|
+
chez "(string<=? ${x} ${y})"
|
|
579
587
|
|
|
580
588
|
extern pure def infixGt(x: String, y: String): Bool =
|
|
581
589
|
js "(${x} > ${y})"
|
|
582
|
-
chez "(
|
|
590
|
+
chez "(string>? ${x} ${y})"
|
|
583
591
|
|
|
584
592
|
extern pure def infixGte(x: String, y: String): Bool =
|
|
585
593
|
js "(${x} >= ${y})"
|
|
586
|
-
chez "(
|
|
594
|
+
chez "(string>=? ${x} ${y})"
|
|
587
595
|
|
|
588
596
|
|
|
589
597
|
// Boolean operations
|
|
@@ -647,10 +655,13 @@ extern pure def bitwiseXor(x: Int, y: Int): Int =
|
|
|
647
655
|
extern pure def toByte(n: Int): Byte =
|
|
648
656
|
js "${n}"
|
|
649
657
|
llvm "%z = trunc %Int ${n} to %Byte ret %Byte %z"
|
|
658
|
+
chez "${n}"
|
|
650
659
|
|
|
651
660
|
extern pure def toInt(n: Byte): Int =
|
|
652
661
|
js "${n}"
|
|
653
662
|
llvm "%z = zext %Byte ${n} to %Int ret %Int %z"
|
|
663
|
+
vm "effekt::toInt(Byte)"
|
|
664
|
+
chez "${n}"
|
|
654
665
|
|
|
655
666
|
|
|
656
667
|
// Undefined and Null
|
|
@@ -666,11 +677,13 @@ extern pure def toInt(n: Byte): Int =
|
|
|
666
677
|
extern pure def undefined[A](): A =
|
|
667
678
|
js "undefined"
|
|
668
679
|
chez "#f"
|
|
680
|
+
vm "effekt::undefined()"
|
|
669
681
|
|
|
670
682
|
/// Is an FFI value undefined?
|
|
671
683
|
extern pure def isUndefined[A](value: A): Bool =
|
|
672
684
|
js "(${value} === undefined || ${value} === null)"
|
|
673
685
|
chez "(eq? ${value} #f)"
|
|
686
|
+
vm "effekt::isUndefined[A](A)"
|
|
674
687
|
|
|
675
688
|
|
|
676
689
|
// Tuples
|
|
@@ -57,14 +57,17 @@ def server(host: String, port: Int, handler: () => Unit / Socket at {io, async,
|
|
|
57
57
|
|
|
58
58
|
namespace examples {
|
|
59
59
|
def helloWorldApp(): Unit / Socket = {
|
|
60
|
-
val request = do receive();
|
|
60
|
+
val request = do receive().toString;
|
|
61
61
|
|
|
62
|
-
println("Received a request: " ++ request
|
|
62
|
+
println("Received a request: " ++ request)
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
do send(
|
|
64
|
+
def respond(s: String): Unit / Socket =
|
|
65
|
+
do send(s.fromString)
|
|
66
|
+
|
|
67
|
+
if (request.startsWith("GET /")) {
|
|
68
|
+
respond("HTTP/1.1 200 OK\r\n\r\nHello from Effekt!")
|
|
66
69
|
} else {
|
|
67
|
-
|
|
70
|
+
respond("HTTP/1.1 400 Bad Request\r\n\r\n")
|
|
68
71
|
}
|
|
69
72
|
do end()
|
|
70
73
|
}
|
|
@@ -62,7 +62,7 @@ def encodeJsonObject[R]{ body: => R / JsonObjectBuilder }: R / emit[String] = {
|
|
|
62
62
|
do emit("{")
|
|
63
63
|
def c(k: String) = {
|
|
64
64
|
if (not(first)) { do emit(",") }
|
|
65
|
-
do emit(escape(k)); do emit(":")
|
|
65
|
+
do emit(escape(k)); do emit(":")
|
|
66
66
|
first = false
|
|
67
67
|
}
|
|
68
68
|
val r = encodeJson {
|
|
@@ -76,7 +76,7 @@ def encodeJsonObject[R]{ body: => R / JsonObjectBuilder }: R / emit[String] = {
|
|
|
76
76
|
/// Main entry point for encoding json.
|
|
77
77
|
/// Emits individual tokens of the resulting json.
|
|
78
78
|
def encodeJson[R]{ body: => R / JsonBuilder }: R / emit[String] = {
|
|
79
|
-
try body() with JsonBuilder {
|
|
79
|
+
try body() with JsonBuilder {
|
|
80
80
|
def null() = { resume(do emit("null")) }
|
|
81
81
|
def bool(v) = { resume(do emit( if(v){ "true" } else { "false" } )) }
|
|
82
82
|
def number(n) = { resume(do emit(show(n))) }
|
|
@@ -112,7 +112,7 @@ def readDouble(): Double / Scan[Char] = {
|
|
|
112
112
|
if (optionally { readIf('.') }) {
|
|
113
113
|
var b = 0.1
|
|
114
114
|
var r = pre.toDouble
|
|
115
|
-
while (optionally[Int] { readDigit() } is Some(d)) {
|
|
115
|
+
while (returning::optionally[Int] { readDigit() } is Some(d)) {
|
|
116
116
|
r = r + b * d.toDouble
|
|
117
117
|
b = b * 0.1
|
|
118
118
|
}
|
|
@@ -126,14 +126,14 @@ def readDouble(): Double / Scan[Char] = {
|
|
|
126
126
|
|
|
127
127
|
def expectString(string: String): Unit / { Scan[Char], Exception[WrongFormat] } =
|
|
128
128
|
for[Char] { string.each } { char =>
|
|
129
|
-
expect
|
|
129
|
+
expect("Expected " ++ string) { readIf(char) }
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/// Read and unescape a string in ""
|
|
133
133
|
def readQuotedString(): Unit / { Scan[Char], emit[Char], Exception[WrongFormat] } = {
|
|
134
134
|
try {
|
|
135
135
|
skipWhitespace()
|
|
136
|
-
expect
|
|
136
|
+
expect("Expected \"") { readIf('"') }
|
|
137
137
|
while(read[Char]() is c and c != '"') {
|
|
138
138
|
c match {
|
|
139
139
|
case '\\' => read[Char]() match {
|
|
@@ -191,7 +191,7 @@ def decodeJsonObject(): Unit / {Scan[Char], JsonObjectBuilder, Exception[WrongFo
|
|
|
191
191
|
}
|
|
192
192
|
do skip[Char]()
|
|
193
193
|
}
|
|
194
|
-
def decodeJsonList(): Unit / {Scan[Char], JsonBuilder, Exception[WrongFormat]} = {
|
|
194
|
+
def decodeJsonList(): Unit / {Scan[Char], JsonBuilder, Exception[WrongFormat]} = {
|
|
195
195
|
var first = true
|
|
196
196
|
expectString("[")
|
|
197
197
|
with boundary
|
|
@@ -278,7 +278,7 @@ def build[R](){ body: => R / JsonBuilder }: (R, JsonValue) = {
|
|
|
278
278
|
}
|
|
279
279
|
(x, r)
|
|
280
280
|
}
|
|
281
|
-
def buildList[R](){ body: => R / JsonBuilder }: (R, List[JsonValue]) = collectList[JsonValue, R] {
|
|
281
|
+
def buildList[R](){ body: => R / JsonBuilder }: (R, List[JsonValue]) = returning::collectList[JsonValue, R] {
|
|
282
282
|
try body() with JsonBuilder {
|
|
283
283
|
def number(n) = { do emit(Number(n)); resume(()) }
|
|
284
284
|
def bool(b) = { do emit(Bool(b)); resume(()) }
|
|
@@ -296,7 +296,7 @@ def buildList[R](){ body: => R / JsonBuilder }: (R, List[JsonValue]) = collectLi
|
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
|
-
def buildDict[R](){ body: => R / JsonObjectBuilder }: (R, List[(String, JsonValue)]) = collectList[(String, JsonValue), R] {
|
|
299
|
+
def buildDict[R](){ body: => R / JsonObjectBuilder }: (R, List[(String, JsonValue)]) = returning::collectList[(String, JsonValue), R] {
|
|
300
300
|
try body() with JsonObjectBuilder {
|
|
301
301
|
def field(k) = resume { {v} =>
|
|
302
302
|
val x = build{v}
|
|
@@ -315,10 +315,12 @@ namespace test {
|
|
|
315
315
|
|
|
316
316
|
// Read quoted string
|
|
317
317
|
feed("\"\ta\n\ra\"") {
|
|
318
|
-
with scanner[Char
|
|
318
|
+
with scanner[Char]
|
|
319
319
|
println(collectString { readQuotedString() })
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
+
println("")
|
|
323
|
+
|
|
322
324
|
// Parse example
|
|
323
325
|
feed("""{ "a": null, "b": [true,false,false,true], "f": 12.532 }"""){
|
|
324
326
|
with scanner[Char]
|
|
@@ -336,8 +338,10 @@ namespace test {
|
|
|
336
338
|
}
|
|
337
339
|
handleJsonBuilder{d}{ decodeJson() }
|
|
338
340
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
+
|
|
342
|
+
println("")
|
|
343
|
+
|
|
344
|
+
try {
|
|
341
345
|
// Encode example
|
|
342
346
|
encodeJson {
|
|
343
347
|
do dict{
|
|
@@ -352,13 +356,15 @@ namespace test {
|
|
|
352
356
|
}
|
|
353
357
|
}
|
|
354
358
|
}
|
|
355
|
-
|
|
359
|
+
|
|
360
|
+
println("")
|
|
361
|
+
|
|
356
362
|
// format with intermediate value
|
|
357
|
-
val j = feed("""{
|
|
358
|
-
"a": null,
|
|
359
|
-
"b": [true, false, false, true], "f": 12.532
|
|
363
|
+
val j = feed[JsonValue]("""{
|
|
364
|
+
"a": null,
|
|
365
|
+
"b": [true, false, false, true], "f": 12.532
|
|
360
366
|
} """){
|
|
361
|
-
with scanner[Char, JsonValue]
|
|
367
|
+
with returning::scanner[Char, JsonValue]
|
|
362
368
|
build {
|
|
363
369
|
decodeJson()
|
|
364
370
|
}.second
|
|
@@ -366,18 +372,20 @@ namespace test {
|
|
|
366
372
|
encodeJson{
|
|
367
373
|
unbuild(j)
|
|
368
374
|
}
|
|
369
|
-
|
|
375
|
+
|
|
376
|
+
println("")
|
|
377
|
+
|
|
370
378
|
// format (minify) example
|
|
371
379
|
encodeJson{
|
|
372
|
-
feed("""{
|
|
373
|
-
"a": null,
|
|
374
|
-
"b": [true, false, false, true], "f": 12.532
|
|
380
|
+
feed("""{
|
|
381
|
+
"a": null,
|
|
382
|
+
"b": [true, false, false, true], "f": 12.532
|
|
375
383
|
} """){
|
|
376
|
-
with scanner[Char
|
|
384
|
+
with scanner[Char]
|
|
377
385
|
decodeJson()
|
|
378
386
|
}
|
|
379
387
|
}
|
|
380
|
-
|
|
388
|
+
|
|
381
389
|
} with emit[String] { e =>
|
|
382
390
|
resume(println(e))
|
|
383
391
|
}
|