@effekt-lang/effekt 0.3.0 → 0.5.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.
Files changed (44) hide show
  1. package/README.md +6 -18
  2. package/bin/effekt +0 -0
  3. package/libraries/common/args.effekt +0 -27
  4. package/libraries/common/array.effekt +34 -63
  5. package/libraries/common/bench.effekt +40 -22
  6. package/libraries/common/buffer.effekt +8 -20
  7. package/libraries/common/bytes.effekt +5 -15
  8. package/libraries/common/dequeue.effekt +5 -5
  9. package/libraries/common/effekt.effekt +51 -92
  10. package/libraries/common/exception.effekt +0 -1
  11. package/libraries/common/io/console.effekt +30 -36
  12. package/libraries/common/io/error.effekt +131 -30
  13. package/libraries/common/io/filesystem.effekt +262 -0
  14. package/libraries/common/io/network.effekt +30 -54
  15. package/libraries/common/io/time.effekt +9 -12
  16. package/libraries/common/io.effekt +54 -124
  17. package/libraries/common/list.effekt +345 -327
  18. package/libraries/common/process.effekt +0 -1
  19. package/libraries/common/queue.effekt +1 -3
  20. package/libraries/common/ref.effekt +11 -24
  21. package/libraries/common/result.effekt +6 -14
  22. package/libraries/common/seq.effekt +28 -49
  23. package/libraries/common/string/tty.effekt +66 -0
  24. package/libraries/common/string.effekt +7 -49
  25. package/libraries/common/test.effekt +96 -34
  26. package/libraries/js/unsafe/cont.effekt +1 -1
  27. package/libraries/llvm/io.c +258 -378
  28. package/libraries/llvm/main.c +3 -0
  29. package/libraries/llvm/rts.ll +57 -38
  30. package/libraries/llvm/types.c +10 -1
  31. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
  32. package/licenses/mit license - mit-license.html +21 -20
  33. package/licenses/the bsd license - bsd-license.html +20 -21
  34. package/licenses/the mit license - mit.html +22 -21
  35. package/package.json +1 -1
  36. package/libraries/chez/lift/effekt.ss +0 -118
  37. package/libraries/common/io/files.effekt +0 -282
  38. package/libraries/js/io.js +0 -143
  39. package/libraries/llvm/io.ll +0 -19
  40. package/libraries/ml/effekt.sml +0 -65
  41. package/libraries/ml/internal/mllist.effekt +0 -9
  42. package/libraries/ml/internal/mloption.effekt +0 -18
  43. package/libraries/ml/random.effekt +0 -85
  44. package/libraries/ml/text/regex.effekt +0 -102
package/README.md CHANGED
@@ -11,26 +11,14 @@ aims to be significantly more lightweight in its concepts.
11
11
  Also, Effekt comes with no warranty and there are (probably) many bugs -- If this does not discourage you, feel free to
12
12
  play with it and give us your feedback :)
13
13
 
14
- ## Installation
15
-
16
- You need to have Java (>= 11) and Node (>= 12) and npm installed.
17
-
18
- The recommended way of installing Effekt is by running:
14
+ ## Examples
19
15
 
20
- ```
21
- npm install -g https://github.com/effekt-lang/effekt/releases/latest/download/effekt.tgz
22
- ```
16
+ If you are looking for examples of the Effekt language, we invite you to look at the [casestudies](https://github.com/effekt-lang/effekt/tree/master/examples/casestudies) and the [language tour](https://effekt-lang.org/tour).
23
17
 
24
- Alternatively, you can download the `effekt.tgz` file from [another release](https://github.com/effekt-lang/effekt/releases) and then run
25
-
26
- ```
27
- npm install -g effekt.tgz
28
- ```
18
+ ## Installation
29
19
 
30
- This will make the `effekt` command globally available. You can start the Effekt REPL by entering:
20
+ Please navigate to the [getting-started guide](https://effekt-lang.org/docs/getting-started#installing-effekt) on our [website](https://effekt-lang.org) for detailed instructions of how to install Effekt.
31
21
 
32
- ```
33
- > effekt
34
- ```
22
+ ## Contributing
35
23
 
36
- You can find more information about the Effekt language and how to use it on the website (<https://effekt-lang.org>).
24
+ Thanks for considering to contribute to the Effekt compiler! For setting up your local environment, please check out our [contributing guide](https://effekt-lang.org/contributing.html) on the [website](https://effekt-lang.org).
package/bin/effekt CHANGED
Binary file
@@ -3,7 +3,6 @@ module args
3
3
  extern io def commandLineArgs(): List[String] =
4
4
  js { js::commandLineArgs() }
5
5
  chez { chez::commandLineArgs() }
6
- ml { ml::commandLineArgs() }
7
6
  llvm { llvm::commandLineArgs() }
8
7
 
9
8
  namespace js {
@@ -46,32 +45,6 @@ namespace chez {
46
45
  def commandLineArgs(): List[String] = nativeArgs().toList
47
46
  }
48
47
 
49
- namespace ml {
50
-
51
- // MLList[String]
52
- // we inline these from mllist to not have a dependency
53
- extern type Args
54
-
55
- extern io def nativeArgs(): Args =
56
- ml "CommandLine.arguments ()"
57
-
58
- extern pure def isEmpty(args: Args): Bool =
59
- ml "null ${args}"
60
-
61
- extern io def first(a: Args): String =
62
- ml "hd ${a}"
63
-
64
- extern io def rest(a: Args): Args =
65
- ml "tl ${a}"
66
-
67
-
68
- def commandLineArgs(): List[String] = {
69
- def toList(args: Args): List[String] =
70
- if (args.isEmpty) Nil() else Cons(args.first, args.rest.toList)
71
- nativeArgs().toList
72
- }
73
- }
74
-
75
48
  namespace llvm {
76
49
  extern io def argCount(): Int =
77
50
  llvm """
@@ -4,15 +4,11 @@ import effekt
4
4
  import exception
5
5
  import list
6
6
 
7
- /**
8
- * A mutable 0-indexed fixed-sized array.
9
- */
7
+ /// A mutable 0-indexed fixed-sized array.
10
8
  extern type Array[T]
11
9
 
12
- /**
13
- * Allocates a new array of size `size`, keeping its values _undefined_.
14
- * Prefer using `array` constructor instead to ensure that values are defined.
15
- */
10
+ /// Allocates a new array of size `size`, keeping its values _undefined_.
11
+ /// Prefer using `array` constructor instead to ensure that values are defined.
16
12
  extern global def allocate[T](size: Int): Array[T] =
17
13
  js "(new Array(${size}))"
18
14
  chez "(make-vector ${size})" // creates an array filled with 0s on CS
@@ -21,22 +17,16 @@ extern global def allocate[T](size: Int): Array[T] =
21
17
  ret %Pos %z
22
18
  """
23
19
 
24
- /**
25
- * Creates a new Array of size `size` filled with the value `init`
26
- */
27
- extern global def array[T](size: Int, init: T): Array[T] =
28
- ml "Array.array (${size}, ${init})"
29
- default {
30
- val arr = allocate[T](size);
31
- each(0, size) { i =>
32
- unsafeSet(arr, i, init)
33
- };
34
- arr
35
- }
20
+ /// Creates a new Array of size `size` filled with the value `init`
21
+ def array[T](size: Int, init: T): Array[T] = {
22
+ val arr = allocate[T](size);
23
+ each(0, size) { i =>
24
+ unsafeSet(arr, i, init)
25
+ };
26
+ arr
27
+ }
36
28
 
37
- /**
38
- * Converts a List `list` to an Array
39
- */
29
+ /// Converts a List `list` to an Array
40
30
  def fromList[T](list: List[T]): Array[T] = {
41
31
  val listSize = list.size();
42
32
  val arr = allocate(listSize);
@@ -47,58 +37,47 @@ def fromList[T](list: List[T]): Array[T] = {
47
37
  return arr;
48
38
  }
49
39
 
50
- /**
51
- * Gets the length of the array in constant time.
52
- */
40
+ /// Gets the length of the array in constant time.
53
41
  extern pure def size[T](arr: Array[T]): Int =
54
42
  js "${arr}.length"
55
43
  chez "(vector-length ${arr})"
56
- ml "Array.length ${arr}"
57
44
  llvm """
58
45
  %z = call %Int @c_array_size(%Pos ${arr})
59
46
  ret %Int %z
60
47
  """
61
48
 
62
- /**
63
- * Gets the element of the `arr` at given `index` in constant time.
64
- * Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size)
65
- *
66
- * Prefer using `get` instead.
67
- */
49
+ /// Gets the element of the `arr` at given `index` in constant time.
50
+ /// Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size)
51
+ ///
52
+ /// Prefer using `get` instead.
68
53
  extern global def unsafeGet[T](arr: Array[T], index: Int): T =
69
54
  js "${arr}[${index}]"
70
55
  chez "(vector-ref ${arr} ${index})"
71
- ml "Array.sub (${arr}, ${index})"
72
56
  llvm """
73
57
  %z = call %Pos @c_array_get(%Pos ${arr}, %Int ${index})
74
58
  ret %Pos %z
75
59
  """
76
60
 
77
61
  extern js """
78
- function array$set(arr, index, value) {
79
- arr[index] = value;
80
- return $effekt.unit
81
- }
62
+ function array$set(arr, index, value) {
63
+ arr[index] = value;
64
+ return $effekt.unit
65
+ }
82
66
  """
83
67
 
84
- /**
85
- * Sets the element of the `arr` at given `index` to `value` in constant time.
86
- * Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size)
87
- *
88
- * Prefer using `set` instead.
89
- */
68
+ /// Sets the element of the `arr` at given `index` to `value` in constant time.
69
+ /// Unchecked Precondition: `index` is in bounds (0 ≤ index < arr.size)
70
+ ///
71
+ /// Prefer using `set` instead.
90
72
  extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit =
91
73
  js "array$set(${arr}, ${index}, ${value})"
92
74
  chez "(begin (vector-set! ${arr} ${index} ${value}) #f)"
93
- ml "Array.update (${arr}, ${index}, ${value})"
94
75
  llvm """
95
76
  %z = call %Pos @c_array_set(%Pos ${arr}, %Int ${index}, %Pos ${value})
96
77
  ret %Pos %z
97
78
  """
98
79
 
99
- /**
100
- * Creates a copy of `arr`
101
- */
80
+ /// Creates a copy of `arr`
102
81
  def copy[T](arr: Array[T]): Array[T] = {
103
82
  with on[OutOfBounds].default { <> }; // should not happen
104
83
  val len = arr.size;
@@ -107,10 +86,8 @@ def copy[T](arr: Array[T]): Array[T] = {
107
86
  newArray
108
87
  }
109
88
 
110
- /**
111
- * Copies `length`-many elements from `from` to `to`
112
- * starting at `start` (in `from`) and `offset` (in `to`)
113
- */
89
+ /// Copies `length`-many elements from `from` to `to`
90
+ /// starting at `start` (in `from`) and `offset` (in `to`)
114
91
  def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int): Unit / Exception[OutOfBounds] = {
115
92
  val startValid = start >= 0 && start + length <= from.size
116
93
  val offsetValid = offset >= 0 && offset + length <= to.size
@@ -127,26 +104,20 @@ def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int):
127
104
 
128
105
  // Derived operations:
129
106
 
130
- /**
131
- * Gets the element of the `arr` at given `index` in constant time,
132
- * throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`.
133
- */
107
+ /// Gets the element of the `arr` at given `index` in constant time,
108
+ /// throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`.
134
109
  def get[T](arr: Array[T], index: Int): T / Exception[OutOfBounds] =
135
110
  if (index >= 0 && index < arr.size) arr.unsafeGet(index)
136
111
  else do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index))
137
112
 
138
- /**
139
- * Sets the element of the `arr` at given `index` to `value` in constant time,
140
- * throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`.
141
- */
113
+ /// Sets the element of the `arr` at given `index` to `value` in constant time,
114
+ /// throwing an `Exception[OutOfBounds]` unless `0 ≤ index < arr.size`.
142
115
  def set[T](arr: Array[T], index: Int, value: T): Unit / Exception[OutOfBounds] =
143
116
  if (index >= 0 && index < arr.size) unsafeSet(arr, index, value)
144
117
  else do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index))
145
118
 
146
- /**
147
- * Builds a new Array of size `size` from a computation `index` which gets an index
148
- * and returns a value that will be on that position in the resulting array
149
- */
119
+ /// Builds a new Array of size `size` from a computation `index` which gets an index
120
+ /// and returns a value that will be on that position in the resulting array
150
121
  def build[T](size: Int) { index: Int => T }: Array[T] = {
151
122
  val arr = allocate[T](size);
152
123
  each(0, size) { i =>
@@ -1,17 +1,15 @@
1
1
  module bench
2
2
 
3
- /**
4
- * The current time (since UNIX Epoch) in nanoseconds.
5
- *
6
- * The actual precision varies across the different backends.
7
- * - js: Milliseconds
8
- * - chez: Microseconds
9
- * - ml: Microseconds
10
- */
11
- extern io def timestamp(): Int =
3
+ type Nanos = Int
4
+
5
+ /// The current time (since UNIX Epoch) in nanoseconds.
6
+ ///
7
+ /// The actual precision varies across the different backends.
8
+ /// - js: Milliseconds
9
+ /// - chez: Microseconds
10
+ extern io def timestamp(): Nanos =
12
11
  js "Date.now() * 1000000"
13
12
  chez "(timestamp)"
14
- ml "IntInf.toInt (Time.toNanoseconds (Time.now ()))"
15
13
  llvm """
16
14
  %time_ptr = alloca { i64, i64 }
17
15
  call i32 @clock_gettime(i32 0, ptr %time_ptr)
@@ -27,24 +25,31 @@ extern llvm """
27
25
  declare i32 @clock_gettime(i32, ptr)
28
26
  """
29
27
 
30
- /**
31
- * High-precision timestamp in nanoseconds that should be for measurements.
32
- *
33
- * This timestamp should only be used for **relative** measurements,
34
- * as gives no guarantees on the absolute time (unlike a UNIX timestamp).
35
- */
36
- extern io def relativeTimestamp(): Int =
28
+ // This should not be needed when using NodeJS 16.x or newer.
29
+ extern jsNode """
30
+ const { performance } = require('node:perf_hooks');
31
+ """
32
+
33
+ /// High-precision timestamp in nanoseconds that should be for measurements.
34
+ ///
35
+ /// This timestamp should only be used for **relative** measurements,
36
+ /// as gives no guarantees on the absolute time (unlike a UNIX timestamp).
37
+ extern io def relativeTimestamp(): Nanos =
37
38
  js "Math.round(performance.now() * 1000000)"
38
39
  default { timestamp() }
39
40
 
40
- /**
41
- * Runs the block and returns the time in nanoseconds
42
- */
43
- def timed { block: => Unit }: Int = {
41
+ type Duration = Int
42
+
43
+ namespace Duration {
44
+ def diff(fromNanos: Nanos, toNanos: Nanos): Duration = toNanos - fromNanos
45
+ }
46
+
47
+ /// Runs the block and returns the time in nanoseconds
48
+ def timed { block: => Unit }: Duration = {
44
49
  val before = relativeTimestamp()
45
50
  block()
46
51
  val after = relativeTimestamp()
47
- after - before
52
+ Duration::diff(before, after)
48
53
  }
49
54
 
50
55
  def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit = {
@@ -58,3 +63,16 @@ def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit = {
58
63
  run(warmup, false)
59
64
  run(iterations, true)
60
65
  }
66
+
67
+ /// Takes a duration in nanoseconds and formats it in milliseconds with precision of two decimal digits.
68
+ def formatMs(nanos: Nanos): String = {
69
+ val micros = nanos / 1000000
70
+ val sub = (nanos.mod(1000000).toDouble / 10000.0).round
71
+
72
+ if (sub == 100) {
73
+ // overflow because of rounding
74
+ (micros + 1).show ++ ".0ms"
75
+ } else {
76
+ micros.show ++ "." ++ sub.show ++ "ms"
77
+ }
78
+ }
@@ -9,34 +9,22 @@ import array
9
9
 
10
10
  record BufferOverflow()
11
11
 
12
- /**
13
- * Fixed-size ring buffers (queues) where one can write
14
- * elements to the head and read from the tail.
15
- */
12
+ /// Fixed-size ring buffers (queues) where one can write
13
+ /// elements to the head and read from the tail.
16
14
  interface Buffer[T] {
17
- /**
18
- * The remaining capacity
19
- */
15
+ /// The remaining capacity
20
16
  def capacity(): Int
21
17
 
22
- /**
23
- * Is this buffer full?
24
- */
18
+ /// Is this buffer full?
25
19
  def full?(): Bool
26
20
 
27
- /**
28
- * Is this buffer empty?
29
- */
21
+ /// Is this buffer empty?
30
22
  def empty?(): Bool
31
23
 
32
- /**
33
- * Read an element from the tail of the buffer
34
- */
24
+ /// Read an element from the tail of the buffer
35
25
  def read(): Option[T]
36
26
 
37
- /**
38
- * Write an element to the head of the buffer
39
- */
27
+ /// Write an element to the head of the buffer
40
28
  def write(el: T): Unit / Exception[BufferOverflow]
41
29
  }
42
30
 
@@ -120,4 +108,4 @@ namespace examples {
120
108
  println(ringbuffer.read());
121
109
  println(ringbuffer.read());
122
110
  }
123
- }
111
+ }
@@ -1,15 +1,11 @@
1
1
  module bytes
2
2
 
3
- /**
4
- * A memory managed, mutable, fixed-length buffer of bytes.
5
- */
3
+ /// A memory managed, mutable, fixed-length buffer of bytes.
6
4
  extern type Bytes
7
5
  // = llvm "%Pos"
8
6
  // = js "Uint8Array"
9
7
 
10
- /**
11
- * Allocates new bytes with the given `capacity`, setting its values to `0`.
12
- */
8
+ /// Allocates new bytes with the given `capacity`, setting its values to `0`.
13
9
  extern io def bytes(capacity: Int): Bytes =
14
10
  js "(new Uint8Array(${capacity}))"
15
11
  llvm """
@@ -55,9 +51,7 @@ extern io def write(b: Bytes, index: Int, value: Byte): Unit =
55
51
  ret %Pos zeroinitializer
56
52
  """
57
53
 
58
- /**
59
- * Returns an *aliased* slice of b starting at offset with the given length
60
- */
54
+ /// Returns an *aliased* slice of b starting at offset with the given length
61
55
  def slice(b: Bytes, offset: Int, length: Int): Bytes = {
62
56
  def validOffset() = offset >= 0 && offset < b.size
63
57
  def validLength() = length >= 0 && (offset + length) <= b.size
@@ -66,9 +60,7 @@ def slice(b: Bytes, offset: Int, length: Int): Bytes = {
66
60
  }
67
61
 
68
62
 
69
- /**
70
- * Returns a view into the buffer, with the length truncated to n
71
- */
63
+ /// Returns a view into the buffer, with the length truncated to n
72
64
  def truncated(b: Bytes, n: Int): Bytes =
73
65
  b.slice(0, n)
74
66
 
@@ -88,9 +80,7 @@ extern pure def toUTF8(b: Bytes): String =
88
80
  """
89
81
 
90
82
  namespace unsafe {
91
- /**
92
- * Unsafe: offset and length are not checked.
93
- */
83
+ /// Unsafe: offset and length are not checked.
94
84
  extern io def slice(b: Bytes, offset: Int, length: Int): Bytes =
95
85
  js "new Uint8Array(${b}.buffer, ${offset}, ${length})"
96
86
  llvm """
@@ -1,11 +1,11 @@
1
1
  module dequeue
2
2
 
3
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
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
9
  record Dequeue[R](front: List[R], frontSize: Int, rear: List[R], rearSize: Int)
10
10
 
11
11
  def emptyQueue[R](): Dequeue[R] = Dequeue(Nil(), 0, Nil(), 0)