@effekt-lang/effekt 0.30.0 → 0.32.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/chez/common/effekt_primitives.ss +1 -0
- package/libraries/common/char.effekt +130 -35
- package/libraries/common/effekt.effekt +25 -1
- package/libraries/common/exception.effekt +1 -1
- package/libraries/common/json.effekt +1 -2
- package/libraries/common/result.effekt +6 -0
- package/libraries/common/scanner.effekt +11 -3
- package/libraries/common/string.effekt +31 -136
- package/libraries/js/effekt_builtins.js +1 -1
- package/libraries/llvm/bytearray.c +1 -1
- package/libraries/llvm/forward-declare-c.ll +2 -4
- package/libraries/llvm/io.c +23 -16
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +2 -2
- package/licenses/mit license - mit-license.html +32 -21
- package/licenses/the bsd license - bsd-license.html +31 -20
- package/licenses/the mit license - mit.html +32 -21
- package/package.json +1 -1
package/bin/effekt
CHANGED
|
Binary file
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/// Warning: This library currently only works with ASCII characters, **not** unicode!
|
|
2
2
|
module char
|
|
3
3
|
|
|
4
|
+
import effekt
|
|
4
5
|
import exception
|
|
6
|
+
import option
|
|
7
|
+
import result
|
|
5
8
|
|
|
6
9
|
|
|
7
10
|
/// Checks if the given character is an ASCII whitespace
|
|
@@ -15,56 +18,51 @@ def isWhitespace(c: Char): Bool = c match {
|
|
|
15
18
|
case _ => false
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
/// Gets the value of a given ASCII digit in base 10
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
/// Gets the value of a given ASCII digit in base 10,
|
|
22
|
+
/// throwing an exception on wrong format
|
|
23
|
+
def digitValue(char: Char): Int / Exception[WrongFormat] =
|
|
21
24
|
if (char >= '0' && char <= '9') {
|
|
22
|
-
|
|
25
|
+
char.toInt - '0'.toInt
|
|
23
26
|
} else {
|
|
24
|
-
|
|
27
|
+
wrongFormat("Not a valid digit: '" ++ char.toString ++ "' in base 10")
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
/// Gets the value of a given ASCII digit in base 16
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
/// Gets the value of a given ASCII digit in base 16,
|
|
31
|
+
/// throwing an exception on wrong format
|
|
32
|
+
def hexDigitValue(char: Char): Int / Exception[WrongFormat] =
|
|
30
33
|
char match {
|
|
31
|
-
case char and char >= '0' && char <= '9' =>
|
|
32
|
-
case char and char >= 'A' && char <= 'F' =>
|
|
33
|
-
case char and char >= 'a' && char <= 'f' =>
|
|
34
|
-
case _ =>
|
|
34
|
+
case char and char >= '0' && char <= '9' => char.toInt - '0'.toInt
|
|
35
|
+
case char and char >= 'A' && char <= 'F' => (char.toInt - 'A'.toInt) + 10
|
|
36
|
+
case char and char >= 'a' && char <= 'f' => (char.toInt - 'a'.toInt) + 10
|
|
37
|
+
case _ => wrongFormat("Not a valid digit: '" ++ char.toString ++ "' in base 16")
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
/// Gets the value of a given ASCII digit in the given base up to 36
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
val
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
perhapsDigit match {
|
|
47
|
-
case Some(digit) =>
|
|
48
|
-
if (digit < base) {
|
|
49
|
-
Some(digit)
|
|
50
|
-
} else {
|
|
51
|
-
None()
|
|
52
|
-
}
|
|
53
|
-
case None() => None()
|
|
40
|
+
/// Gets the value of a given ASCII digit in the given base up to 36,
|
|
41
|
+
/// throwing an exception on wrong format
|
|
42
|
+
def digitValue(char: Char, base: Int): Int / Exception[WrongFormat] = {
|
|
43
|
+
val digit = char match {
|
|
44
|
+
case char and char >= '0' && char <= '9' => char.toInt - '0'.toInt
|
|
45
|
+
case char and char >= 'A' && char <= 'Z' => (char.toInt - 'A'.toInt) + 10
|
|
46
|
+
case char and char >= 'a' && char <= 'z' => (char.toInt - 'a'.toInt) + 10
|
|
47
|
+
case _ => wrongFormat("Not a valid digit: '" ++ char.toString ++ "'")
|
|
54
48
|
}
|
|
49
|
+
if (digit >= base) {
|
|
50
|
+
wrongFormat("Digit '" ++ digit.show ++ "' is too big for base " ++ base.show)
|
|
51
|
+
}
|
|
52
|
+
digit
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
/// Checks if the given character is an ASCII digit in base 10
|
|
58
|
-
///
|
|
59
|
-
def isDigit(char: Char): Bool = digitValue(char).
|
|
56
|
+
/// Prefer using `digitValue(c: Char)` to get the numeric value out.
|
|
57
|
+
def isDigit(char: Char): Bool = result[Int, WrongFormat] { digitValue(char) }.isSuccess
|
|
60
58
|
|
|
61
59
|
/// Checks if the given character is an ASCII digit in base 16
|
|
62
|
-
///
|
|
63
|
-
def isHexDigit(char: Char): Bool = hexDigitValue(char).
|
|
60
|
+
/// Prefer using `hexDigitValue(c: Char)` to get the numeric value out.
|
|
61
|
+
def isHexDigit(char: Char): Bool = result[Int, WrongFormat] { hexDigitValue(char)}.isSuccess
|
|
64
62
|
|
|
65
63
|
/// Checks if the given character is an ASCII digit in base 10
|
|
66
|
-
///
|
|
67
|
-
def isDigit(char: Char, base: Int): Bool = digitValue(char, base).
|
|
64
|
+
/// Prefer using `digitValue(c: Char, base: Int)` to get the numeric value out.
|
|
65
|
+
def isDigit(char: Char, base: Int): Bool = result[Int, WrongFormat] { digitValue(char, base) }.isSuccess
|
|
68
66
|
|
|
69
67
|
/// Checks if a given character is a 7-bit ASCII character
|
|
70
68
|
def isASCII(c: Char): Bool = { c.toInt < 128 }
|
|
@@ -80,3 +78,100 @@ def isAlphanumeric(c: Char): Bool = isDigit(c) || isLower(c) || isUpper(c)
|
|
|
80
78
|
|
|
81
79
|
/// Checks if a given character is an ASCII alphabetic character
|
|
82
80
|
def isAlphabetic(c: Char): Bool = isLower(c) || isUpper(c)
|
|
81
|
+
|
|
82
|
+
// Characters
|
|
83
|
+
// ----------
|
|
84
|
+
//
|
|
85
|
+
// JS: Int (Unicode codepoints)
|
|
86
|
+
// Chez: ?
|
|
87
|
+
// LLVM: i64 representing utf-8 (varying length 1-4 bytes)
|
|
88
|
+
|
|
89
|
+
extern pure def toString(ch: Char): String =
|
|
90
|
+
js "String.fromCodePoint(${ch})"
|
|
91
|
+
chez "(string (integer->char ${ch}))"
|
|
92
|
+
llvm """
|
|
93
|
+
%z = call %Pos @c_bytearray_show_Char(%Int ${ch})
|
|
94
|
+
ret %Pos %z
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
// Since we currently represent Char by integers in all backends, we could reuse comparison
|
|
98
|
+
extern pure def toInt(ch: Char): Int =
|
|
99
|
+
js "${ch}"
|
|
100
|
+
chez "${ch}"
|
|
101
|
+
llvm "ret %Int ${ch}"
|
|
102
|
+
vm "string::toInt(Char)"
|
|
103
|
+
|
|
104
|
+
extern pure def toChar(codepoint: Int): Char =
|
|
105
|
+
js "${codepoint}"
|
|
106
|
+
chez "${codepoint}"
|
|
107
|
+
llvm "ret %Int ${codepoint}"
|
|
108
|
+
vm "string::toChar(Int)"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
extern pure def infixLt(x: Char, y: Char): Bool =
|
|
112
|
+
js "(${x} < ${y})"
|
|
113
|
+
chez "(< ${x} ${y})"
|
|
114
|
+
llvm """
|
|
115
|
+
%z = icmp slt %Int ${x}, ${y}
|
|
116
|
+
%fat_z = zext i1 %z to i64
|
|
117
|
+
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
118
|
+
ret %Pos %adt_boolean
|
|
119
|
+
"""
|
|
120
|
+
vm "string::infixLt(Char, Char)"
|
|
121
|
+
|
|
122
|
+
extern pure def infixLte(x: Char, y: Char): Bool =
|
|
123
|
+
js "(${x} <= ${y})"
|
|
124
|
+
chez "(<= ${x} ${y})"
|
|
125
|
+
llvm """
|
|
126
|
+
%z = icmp sle %Int ${x}, ${y}
|
|
127
|
+
%fat_z = zext i1 %z to i64
|
|
128
|
+
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
129
|
+
ret %Pos %adt_boolean
|
|
130
|
+
"""
|
|
131
|
+
vm "string::infixLte(Char, Char)"
|
|
132
|
+
|
|
133
|
+
extern pure def infixGt(x: Char, y: Char): Bool =
|
|
134
|
+
js "(${x} > ${y})"
|
|
135
|
+
chez "(> ${x} ${y})"
|
|
136
|
+
llvm """
|
|
137
|
+
%z = icmp sgt %Int ${x}, ${y}
|
|
138
|
+
%fat_z = zext i1 %z to i64
|
|
139
|
+
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
140
|
+
ret %Pos %adt_boolean
|
|
141
|
+
"""
|
|
142
|
+
vm "string::infixGt(Char, Char)"
|
|
143
|
+
|
|
144
|
+
extern pure def infixGte(x: Char, y: Char): Bool =
|
|
145
|
+
js "(${x} >= ${y})"
|
|
146
|
+
chez "(>= ${x} ${y})"
|
|
147
|
+
llvm """
|
|
148
|
+
%z = icmp sge %Int ${x}, ${y}
|
|
149
|
+
%fat_z = zext i1 %z to i64
|
|
150
|
+
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
151
|
+
ret %Pos %adt_boolean
|
|
152
|
+
"""
|
|
153
|
+
vm "string::infixGte(Char, Char)"
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Determines the number of bytes needed by a codepoint
|
|
158
|
+
*
|
|
159
|
+
* Also see: https://en.wikipedia.org/wiki/UTF-8
|
|
160
|
+
*/
|
|
161
|
+
def utf8ByteCount(codepoint: Char): Int = codepoint match {
|
|
162
|
+
case c and c >= \u0000 and c <= \u007F => 1
|
|
163
|
+
case c and c >= \u0080 and c <= \u07FF => 2
|
|
164
|
+
case c and c >= \u0800 and c <= \uFFFF => 3
|
|
165
|
+
case c and c >= \u10000 and c <= \u10FFFF => 4
|
|
166
|
+
case c => panic("Not a valid code point")
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
def utf16UnitCount(codepoint: Char): Int = codepoint match {
|
|
170
|
+
case c and c >= \u0000 and c <= \uFFFF => 1
|
|
171
|
+
case c and c >= \u10000 and c <= \u10FFFF => 4
|
|
172
|
+
case c => panic("Not a valid code point")
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
extern pure def charWidth(c: Char): Int =
|
|
176
|
+
// JavaScript strings are UTF-16 where every unicode character after 0xffff takes two units
|
|
177
|
+
js "(${c} > 0xffff) ? 2 : 1"
|
|
@@ -42,11 +42,32 @@ extern def println(value: String): Unit =
|
|
|
42
42
|
js "$effekt.println(${value})"
|
|
43
43
|
chez "(println_impl ${value})"
|
|
44
44
|
llvm """
|
|
45
|
-
call void @
|
|
45
|
+
call void @c_io_println(%Pos ${value})
|
|
46
46
|
ret %Pos zeroinitializer ; Unit
|
|
47
47
|
"""
|
|
48
48
|
vm "effekt::println(String)"
|
|
49
49
|
|
|
50
|
+
extern jsNode """
|
|
51
|
+
$effekt.readln = function readln$impl(callback) {
|
|
52
|
+
const readline = require('node:readline').createInterface({
|
|
53
|
+
input: process.stdin,
|
|
54
|
+
output: process.stdout,
|
|
55
|
+
});
|
|
56
|
+
readline.question('', (answer) => {
|
|
57
|
+
readline.close();
|
|
58
|
+
callback(answer);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
extern async def readln(): String =
|
|
64
|
+
jsNode "$effekt.capture(callback => $effekt.readln(callback))"
|
|
65
|
+
llvm """
|
|
66
|
+
%result = call %Pos @c_io_readln()
|
|
67
|
+
tail call void @resume_Pos(%Stack %stack, %Pos %result)
|
|
68
|
+
ret void
|
|
69
|
+
"""
|
|
70
|
+
|
|
50
71
|
def println(value: Int): Unit = println(value.show)
|
|
51
72
|
def println(value: Unit): Unit = println(value.show)
|
|
52
73
|
def println(value: Double): Unit = println(value.show)
|
|
@@ -736,6 +757,9 @@ def repeat(n: Int) { action: () => Unit } = each(0, n) { n => action() }
|
|
|
736
757
|
|
|
737
758
|
def repeat(n: Int) { action: () {Control} => Unit } = each(0, n) { (n) {l} => action() {l} }
|
|
738
759
|
|
|
760
|
+
// NOTE: This is emitted by the close hole code action: do not remove unless you also adjust the code action
|
|
761
|
+
/// Scopes a local computation
|
|
762
|
+
def locally[R] { p: => R } : R = p()
|
|
739
763
|
|
|
740
764
|
// Splices
|
|
741
765
|
// =======
|
|
@@ -54,7 +54,7 @@ extern io def panic(msg: String): Nothing =
|
|
|
54
54
|
js "(function() { throw ${msg} })()"
|
|
55
55
|
chez "(raise ${msg})"
|
|
56
56
|
llvm """
|
|
57
|
-
call void @
|
|
57
|
+
call void @c_io_println(%Pos ${msg})
|
|
58
58
|
call void @exit(i32 1)
|
|
59
59
|
ret %Pos zeroinitializer ; Unit
|
|
60
60
|
"""
|
|
@@ -35,3 +35,9 @@ def toOption[A, E](r: Result[A, E]): Option[A] = r match {
|
|
|
35
35
|
case Success(a) => Some(a)
|
|
36
36
|
case Error(exc, msg) => None()
|
|
37
37
|
}
|
|
38
|
+
|
|
39
|
+
def isError[A, E](r: Result[A, E]): Bool =
|
|
40
|
+
if (r is Error(_, _)) true else false
|
|
41
|
+
|
|
42
|
+
def isSuccess[A, E](r: Result[A, E]): Bool =
|
|
43
|
+
if (r is Success(_)) true else false
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
module scanner
|
|
2
2
|
|
|
3
|
-
import char
|
|
4
3
|
import stream
|
|
5
4
|
|
|
6
5
|
interface Scan[A] {
|
|
@@ -49,6 +48,15 @@ def readSome[A, B] { convert: A => Option[B] }: B / { Scan[A], stop } =
|
|
|
49
48
|
do stop()
|
|
50
49
|
}
|
|
51
50
|
|
|
51
|
+
/// like `readSome`, but for functions `A => B / Exception[WrongFormat]` such as `char::digitValue`
|
|
52
|
+
def tryRead[A, B] { convert: A => B / Exception[WrongFormat] }: B / { Scan[A], stop } = {
|
|
53
|
+
with on[WrongFormat].default { do stop() }
|
|
54
|
+
|
|
55
|
+
val t = convert(do peek())
|
|
56
|
+
do skip[A]()
|
|
57
|
+
return t
|
|
58
|
+
}
|
|
59
|
+
|
|
52
60
|
/// Reads until the predicate does not hold for the next token.
|
|
53
61
|
/// Emits the tokens read.
|
|
54
62
|
def readWhile[A] { predicate: A => Bool }: Unit / { Scan[A], emit[A] } =
|
|
@@ -78,7 +86,7 @@ def readString(string: String): Unit / { Scan[Char], stop } =
|
|
|
78
86
|
|
|
79
87
|
/// Check that the next character is a digit in base 10, and if so read and return it.
|
|
80
88
|
def readDigit(): Int / { Scan[Char], stop } =
|
|
81
|
-
|
|
89
|
+
tryRead[Char, Int]{ char => digitValue(char) }
|
|
82
90
|
|
|
83
91
|
/// Read a positive decimal number.
|
|
84
92
|
def readDecimal(): Int / Scan[Char] = {
|
|
@@ -91,7 +99,7 @@ def readDecimal(): Int / Scan[Char] = {
|
|
|
91
99
|
|
|
92
100
|
/// Check that the next character is a digit in base 16, and if so read and return it.
|
|
93
101
|
def readHexDigit(): Int / { Scan[Char], stop } =
|
|
94
|
-
|
|
102
|
+
tryRead[Char, Int]{ char => hexDigitValue(char) }
|
|
95
103
|
|
|
96
104
|
/// Read a hexadecimal number.
|
|
97
105
|
def readHexadecimal(): Int / Scan[Char] = {
|
|
@@ -5,6 +5,7 @@ import option
|
|
|
5
5
|
import list
|
|
6
6
|
import exception
|
|
7
7
|
import result
|
|
8
|
+
import char
|
|
8
9
|
|
|
9
10
|
// TODO
|
|
10
11
|
// - [ ] handle unicode codepoints (that can span two indices) correctly
|
|
@@ -61,12 +62,22 @@ def endsWith(str: String, suffix: String): Bool =
|
|
|
61
62
|
/// TODO use a more efficient way of appending strings like a buffer
|
|
62
63
|
def repeat(str: String, n: Int): String = {
|
|
63
64
|
def go(n: Int, result: String): String = {
|
|
64
|
-
if (n
|
|
65
|
+
if (n <= 0) result
|
|
65
66
|
else go(n - 1, result ++ str)
|
|
66
67
|
}
|
|
67
68
|
go(n, "")
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
/// Left-pad the given string with spaces
|
|
72
|
+
def padLeft(str: String, n: Int): String = {
|
|
73
|
+
" ".repeat(n - str.length) ++ str
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// Right-pad the given string with spaces
|
|
77
|
+
def padRight(str: String, n: Int): String = {
|
|
78
|
+
str ++ " ".repeat(n - str.length)
|
|
79
|
+
}
|
|
80
|
+
|
|
70
81
|
// TODO use .split() in JS
|
|
71
82
|
def split(str: String, sep: String): List[String] = {
|
|
72
83
|
val strLength = str.length
|
|
@@ -113,20 +124,18 @@ def toBool(s: String): Bool / Exception[WrongFormat] = s match {
|
|
|
113
124
|
|
|
114
125
|
// TODO optimize (right now this will be horribly slow (compared to the native JS version)
|
|
115
126
|
def toInt(str: String): Int / Exception[WrongFormat] = {
|
|
116
|
-
|
|
117
|
-
val zero = '0'.toInt
|
|
118
|
-
|
|
119
127
|
def go(index: Int, acc: Int): Int = {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
128
|
+
// wrong index means we're done parsing
|
|
129
|
+
with on[OutOfBounds].default { () => acc };
|
|
130
|
+
|
|
131
|
+
val c = str.charAt(index)
|
|
132
|
+
val d = char::digitValue(c)
|
|
133
|
+
go(index + 1, 10 * acc + d)
|
|
127
134
|
}
|
|
128
135
|
|
|
129
|
-
with
|
|
136
|
+
with on[OutOfBounds].default {
|
|
137
|
+
wrongFormat("Empty string is not a valid number")
|
|
138
|
+
}
|
|
130
139
|
|
|
131
140
|
str.charAt(0) match {
|
|
132
141
|
case '-' => 0 - go(1, 0)
|
|
@@ -136,38 +145,22 @@ def toInt(str: String): Int / Exception[WrongFormat] = {
|
|
|
136
145
|
|
|
137
146
|
// TODO optimize (right now this will be horribly slow (compared to the native JS version)
|
|
138
147
|
def toInt(str: String, base: Int): Int / Exception[WrongFormat] = {
|
|
139
|
-
|
|
140
|
-
if( base > 36 || base < 1 ) {
|
|
148
|
+
if (base > 36 || base < 1) {
|
|
141
149
|
wrongFormat("Invalid base: " ++ base.show)
|
|
142
150
|
}
|
|
143
151
|
|
|
144
|
-
val zero = '0'.toInt
|
|
145
|
-
val l_a = 'a'.toInt
|
|
146
|
-
val u_a = 'A'.toInt
|
|
147
|
-
|
|
148
|
-
def parseDigit(c: Char): Option[Int] = {
|
|
149
|
-
if( c >= '0' and c <= '9' and c.toInt - zero < base ) {
|
|
150
|
-
Some(c.toInt - zero)
|
|
151
|
-
} else if( c >= 'a' and c <= 'z' and c.toInt - l_a < base - 10 ) {
|
|
152
|
-
Some(c.toInt - l_a + 10)
|
|
153
|
-
} else if( c >= 'A' and c <= 'Z' and c.toInt - u_a < base - 10) {
|
|
154
|
-
Some(c.toInt - u_a + 10)
|
|
155
|
-
} else {
|
|
156
|
-
None()
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
152
|
def go(index: Int, acc: Int): Int = {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
153
|
+
// wrong index means we're done parsing
|
|
154
|
+
with on[OutOfBounds].default { () => acc };
|
|
155
|
+
|
|
156
|
+
val c = str.charAt(index)
|
|
157
|
+
val d = char::digitValue(c, base)
|
|
158
|
+
go(index + 1, base * acc + d)
|
|
168
159
|
}
|
|
169
160
|
|
|
170
|
-
with
|
|
161
|
+
with on[OutOfBounds].default {
|
|
162
|
+
wrongFormat("Empty string is not a valid number")
|
|
163
|
+
}
|
|
171
164
|
|
|
172
165
|
str.charAt(0) match {
|
|
173
166
|
case '-' => 0 - go(1, 0)
|
|
@@ -222,104 +215,6 @@ def lastIndexOf(str: String, sub: String, from: Int): Option[Int] = {
|
|
|
222
215
|
// extern pure def unsafeIndexOf(str: String, sub: String): Int =
|
|
223
216
|
// js "${str}.indexOf(${sub})"
|
|
224
217
|
|
|
225
|
-
|
|
226
|
-
// Characters
|
|
227
|
-
// ----------
|
|
228
|
-
//
|
|
229
|
-
// JS: Int (Unicode codepoints)
|
|
230
|
-
// Chez: ?
|
|
231
|
-
// LLVM: i64 representing utf-8 (varying length 1-4 bytes)
|
|
232
|
-
|
|
233
|
-
extern pure def toString(ch: Char): String =
|
|
234
|
-
js "String.fromCodePoint(${ch})"
|
|
235
|
-
chez "(string (integer->char ${ch}))"
|
|
236
|
-
llvm """
|
|
237
|
-
%z = call %Pos @c_bytearray_show_Char(%Int ${ch})
|
|
238
|
-
ret %Pos %z
|
|
239
|
-
"""
|
|
240
|
-
|
|
241
|
-
// Since we currently represent Char by integers in all backends, we could reuse comparison
|
|
242
|
-
extern pure def toInt(ch: Char): Int =
|
|
243
|
-
js "${ch}"
|
|
244
|
-
chez "${ch}"
|
|
245
|
-
llvm "ret %Int ${ch}"
|
|
246
|
-
vm "string::toInt(Char)"
|
|
247
|
-
|
|
248
|
-
extern pure def toChar(codepoint: Int): Char =
|
|
249
|
-
js "${codepoint}"
|
|
250
|
-
chez "${codepoint}"
|
|
251
|
-
llvm "ret %Int ${codepoint}"
|
|
252
|
-
vm "string::toChar(Int)"
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
extern pure def infixLt(x: Char, y: Char): Bool =
|
|
256
|
-
js "(${x} < ${y})"
|
|
257
|
-
chez "(< ${x} ${y})"
|
|
258
|
-
llvm """
|
|
259
|
-
%z = icmp slt %Int ${x}, ${y}
|
|
260
|
-
%fat_z = zext i1 %z to i64
|
|
261
|
-
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
262
|
-
ret %Pos %adt_boolean
|
|
263
|
-
"""
|
|
264
|
-
vm "string::infixLt(Char, Char)"
|
|
265
|
-
|
|
266
|
-
extern pure def infixLte(x: Char, y: Char): Bool =
|
|
267
|
-
js "(${x} <= ${y})"
|
|
268
|
-
chez "(<= ${x} ${y})"
|
|
269
|
-
llvm """
|
|
270
|
-
%z = icmp sle %Int ${x}, ${y}
|
|
271
|
-
%fat_z = zext i1 %z to i64
|
|
272
|
-
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
273
|
-
ret %Pos %adt_boolean
|
|
274
|
-
"""
|
|
275
|
-
vm "string::infixLte(Char, Char)"
|
|
276
|
-
|
|
277
|
-
extern pure def infixGt(x: Char, y: Char): Bool =
|
|
278
|
-
js "(${x} > ${y})"
|
|
279
|
-
chez "(> ${x} ${y})"
|
|
280
|
-
llvm """
|
|
281
|
-
%z = icmp sgt %Int ${x}, ${y}
|
|
282
|
-
%fat_z = zext i1 %z to i64
|
|
283
|
-
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
284
|
-
ret %Pos %adt_boolean
|
|
285
|
-
"""
|
|
286
|
-
vm "string::infixGt(Char, Char)"
|
|
287
|
-
|
|
288
|
-
extern pure def infixGte(x: Char, y: Char): Bool =
|
|
289
|
-
js "(${x} >= ${y})"
|
|
290
|
-
chez "(>= ${x} ${y})"
|
|
291
|
-
llvm """
|
|
292
|
-
%z = icmp sge %Int ${x}, ${y}
|
|
293
|
-
%fat_z = zext i1 %z to i64
|
|
294
|
-
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
295
|
-
ret %Pos %adt_boolean
|
|
296
|
-
"""
|
|
297
|
-
vm "string::infixGte(Char, Char)"
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Determines the number of bytes needed by a codepoint
|
|
302
|
-
*
|
|
303
|
-
* Also see: https://en.wikipedia.org/wiki/UTF-8
|
|
304
|
-
*/
|
|
305
|
-
def utf8ByteCount(codepoint: Char): Int = codepoint match {
|
|
306
|
-
case c and c >= \u0000 and c <= \u007F => 1
|
|
307
|
-
case c and c >= \u0080 and c <= \u07FF => 2
|
|
308
|
-
case c and c >= \u0800 and c <= \uFFFF => 3
|
|
309
|
-
case c and c >= \u10000 and c <= \u10FFFF => 4
|
|
310
|
-
case c => panic("Not a valid code point")
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
def utf16UnitCount(codepoint: Char): Int = codepoint match {
|
|
314
|
-
case c and c >= \u0000 and c <= \uFFFF => 1
|
|
315
|
-
case c and c >= \u10000 and c <= \u10FFFF => 4
|
|
316
|
-
case c => panic("Not a valid code point")
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
extern pure def charWidth(c: Char): Int =
|
|
320
|
-
// JavaScript strings are UTF-16 where every unicode character after 0xffff takes two units
|
|
321
|
-
js "(${c} > 0xffff) ? 2 : 1"
|
|
322
|
-
|
|
323
218
|
def charAt(str: String, index: Int): Char / Exception[OutOfBounds] =
|
|
324
219
|
if (index < 0 || index >= length(str))
|
|
325
220
|
do raise(OutOfBounds(), "Index out of bounds: " ++ show(index) ++ " in string: '" ++ str ++ "'")
|
|
@@ -72,7 +72,7 @@ struct Pos c_bytearray_from_nullterminated_string(const char *data) {
|
|
|
72
72
|
char* c_bytearray_into_nullterminated_string(const struct Pos arr) {
|
|
73
73
|
uint64_t size = arr.tag;
|
|
74
74
|
|
|
75
|
-
char* result =
|
|
75
|
+
char* result = malloc(size + 1);
|
|
76
76
|
|
|
77
77
|
memcpy(result, c_bytearray_data(arr), size);
|
|
78
78
|
|
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
declare i64 @c_get_argc()
|
|
4
4
|
declare %Pos @c_get_arg(i64)
|
|
5
5
|
|
|
6
|
-
declare void @
|
|
7
|
-
declare
|
|
8
|
-
declare void @c_io_println_Double(%Double)
|
|
9
|
-
declare void @c_io_println_String(%Pos)
|
|
6
|
+
declare void @c_io_println(%Pos)
|
|
7
|
+
declare %Pos @c_io_readln()
|
|
10
8
|
|
|
11
9
|
declare void @hole()
|
|
12
10
|
declare void @duplicated_prompt()
|
package/libraries/llvm/io.c
CHANGED
|
@@ -4,28 +4,35 @@
|
|
|
4
4
|
#include <uv.h>
|
|
5
5
|
#include <string.h> // to compare flag names
|
|
6
6
|
|
|
7
|
-
// Println
|
|
8
|
-
//
|
|
7
|
+
// Println and Readln
|
|
8
|
+
// ------------------
|
|
9
9
|
|
|
10
|
-
void
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
void c_io_println_Boolean(const struct Pos p) {
|
|
15
|
-
printf("%s\n", p.tag ? "true" : "false");
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
void c_io_println_Double(const Double x) {
|
|
19
|
-
printf("%g\n", x);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
void c_io_println_String(String text) {
|
|
23
|
-
for (uint64_t j = 0; j < text.tag; ++j)
|
|
10
|
+
void c_io_println(String text) {
|
|
11
|
+
for (uint64_t j = 0; j < text.tag; ++j) {
|
|
24
12
|
putchar(c_bytearray_data(text)[j]);
|
|
13
|
+
};
|
|
25
14
|
erasePositive(text);
|
|
26
15
|
putchar('\n');
|
|
27
16
|
}
|
|
28
17
|
|
|
18
|
+
String c_io_readln() {
|
|
19
|
+
uint64_t capacity = 64;
|
|
20
|
+
uint64_t length = 0;
|
|
21
|
+
char* buffer = malloc(capacity * sizeof(char));
|
|
22
|
+
|
|
23
|
+
for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {
|
|
24
|
+
if (length >= capacity) {
|
|
25
|
+
capacity *= 2;
|
|
26
|
+
buffer = realloc(buffer, capacity * sizeof(char));
|
|
27
|
+
}
|
|
28
|
+
buffer[length] = (char)c;
|
|
29
|
+
length++;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
String result = c_bytearray_construct(length, (const uint8_t*)buffer);
|
|
33
|
+
free(buffer);
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
29
36
|
|
|
30
37
|
// Lib UV Bindings
|
|
31
38
|
// ---------------
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Eclipse Public License 2.0 (EPL) | The Eclipse Foundation</title>
|
|
2
|
-
<meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.144.2"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=
|
|
2
|
+
<meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.144.2"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1748196930"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
|
|
3
3
|
<i class="fa fa-search fa-lg" aria-role=none></i></button><div class="toolbar-search-bar-wrapper dropdown-menu dropdown-menu-right" aria-labelledby=toolbar-search><form action=https://www.eclipse.org/home/search method=get><div class=search-bar><input class=search-bar-input name=q placeholder=Search>
|
|
4
4
|
<button>
|
|
5
5
|
<i class="fa fa-search" type=submit></i></button></div></form></div></div><div class="toolbar-btn toolbar-user-menu-btn dropdown"><button class=dropdown-toggle id=toolbar-user-menu type=button data-toggle=dropdown tabindex=0 aria-label="User Menu">
|
|
@@ -60,4 +60,4 @@ open source software collaboration and innovation.</p></div><div class=mega-menu
|
|
|
60
60
|
<i class="fa-brands fa-linkedin-in fa-stack-1x fa-inverse" aria-hidden=true></i>
|
|
61
61
|
<span class=sr-only>Linkedin account</span></span></a></li></ul></div></div><div class="footer-sections row equal-height-md font-bold"><div class=col-md-15><div class=row><section id=footer-eclipse-foundation class="footer-section col-sm-8"><div class=menu-heading>Eclipse Foundation</div><ul class=nav><li><a href=https://www.eclipse.org/org/>About</a></li><li><a href=https://projects.eclipse.org/>Projects</a></li><li><a href=https://www.eclipse.org/collaborations/>Collaborations</a></li><li><a href=https://www.eclipse.org/membership/>Membership</a></li><li><a href=https://www.eclipse.org/sponsor/>Sponsor</a></li></ul></section><section id=footer-legal class="footer-section col-sm-8"><div class=menu-heading>Legal</div><ul class=nav><li><a href=https://www.eclipse.org/legal/privacy/>Privacy Policy</a></li><li><a href=https://www.eclipse.org/legal/terms-of-use/>Terms of Use</a></li><li><a href=https://www.eclipse.org/legal/compliance/>Compliance</a></li><li><a href=https://www.eclipse.org/org/documents/Community_Code_of_Conduct.php>Code of Conduct</a></li><li><a href=https://www.eclipse.org/legal/>Legal Resources</a></li><li><a class=toolbar-manage-cookies href=# onclick=event.preventDefault()>Manage Cookies</a></li></ul></section><section id=footer-more class="footer-section col-sm-8"><div class=menu-heading>More</div><ul class=nav><li><a href=https://www.eclipse.org/security/>Report a Vulnerability</a></li><li><a href=https://status.eclipse.org/>Service Status</a></li><li><a href=https://www.eclipse.org/org/foundation/contact.php>Contact Us</a></li><li><a href=https://www.eclipse.org/projects/support/>Support</a></li></ul></section></div></div><div id=footer-end class="footer-section col-md-8 col-md-offset-1 col-sm-24"><div class=footer-end-newsletter><form id=mc-embedded-subscribe-form action="https://eclipse.us6.list-manage.com/subscribe/post?u=eaf9e1f06f194eadc66788a85&id=e7538485cd&f_id=00f9c2e1f0" method=post novalidate target=_blank><label class=footer-end-newsletter-label for=email>Subscribe to our Newsletter</label><div class=footer-end-newsletter-input-wrapper><input class=footer-end-newsletter-input type=email id=email name=EMAIL autocomplete=email placeholder="Enter your email address">
|
|
62
62
|
<button class="footer-end-newsletter-submit btn btn-link" id=mc-embedded-subscribe type=submit name=subscribe>
|
|
63
|
-
<i class="fa fa-solid fa-envelope fa-lg" aria-hidden=true></i></button></div></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright © Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=
|
|
63
|
+
<i class="fa fa-solid fa-envelope fa-lg" aria-hidden=true></i></button></div></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright © Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1748196930"></script><script>(function(){})(jQuery,document)</script></div></body></html>
|