@effekt-lang/effekt 0.2.2 → 0.4.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 (95) hide show
  1. package/README.md +6 -18
  2. package/bin/effekt +0 -0
  3. package/bin/effekt.sh +1 -1
  4. package/libraries/chez/common/effekt_primitives.ss +10 -2
  5. package/libraries/chez/common/immutable/cslist.effekt +13 -7
  6. package/libraries/chez/common/mutable/dict.effekt +8 -10
  7. package/libraries/chez/common/text/regex.effekt +7 -9
  8. package/libraries/common/args.effekt +68 -0
  9. package/libraries/common/array.effekt +220 -0
  10. package/libraries/common/bench.effekt +86 -0
  11. package/libraries/common/buffer.effekt +123 -0
  12. package/libraries/common/bytes.effekt +125 -0
  13. package/libraries/{js/immutable → common}/dequeue.effekt +18 -4
  14. package/libraries/common/effekt.effekt +725 -0
  15. package/libraries/common/exception.effekt +121 -0
  16. package/libraries/common/io/console.effekt +62 -0
  17. package/libraries/common/io/error.effekt +474 -0
  18. package/libraries/common/io/filesystem.effekt +274 -0
  19. package/libraries/common/io/network.effekt +81 -0
  20. package/libraries/common/io/time.effekt +12 -0
  21. package/libraries/common/io.effekt +88 -0
  22. package/libraries/{llvm/immutable → common}/list.effekt +101 -74
  23. package/libraries/common/option.effekt +72 -0
  24. package/libraries/common/process.effekt +9 -0
  25. package/libraries/common/queue.effekt +140 -0
  26. package/libraries/common/ref.effekt +60 -0
  27. package/libraries/common/result.effekt +45 -0
  28. package/libraries/{ml/immutable → common}/seq.effekt +30 -19
  29. package/libraries/common/string/tty.effekt +66 -0
  30. package/libraries/common/string.effekt +361 -0
  31. package/libraries/common/test.effekt +160 -0
  32. package/libraries/js/effekt_builtins.js +37 -6
  33. package/libraries/js/mutable/map.effekt +8 -9
  34. package/libraries/js/text/regex.effekt +7 -8
  35. package/libraries/js/unsafe/cont.effekt +2 -2
  36. package/libraries/js/web/dom.effekt +13 -13
  37. package/libraries/llvm/array.c +53 -0
  38. package/libraries/llvm/buffer.c +181 -76
  39. package/libraries/llvm/forward-declare-c.ll +27 -8
  40. package/libraries/llvm/io.c +423 -1
  41. package/libraries/llvm/main.c +6 -1
  42. package/libraries/llvm/ref.c +45 -0
  43. package/libraries/llvm/rts.ll +515 -354
  44. package/libraries/llvm/types.c +32 -0
  45. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
  46. package/licenses/mit license - mit-license.html +532 -62
  47. package/licenses/the bsd license - bsd-license.html +535 -60
  48. package/licenses/the mit license - mit.html +532 -62
  49. package/package.json +2 -2
  50. package/libraries/chez/callcc/effekt.effekt +0 -221
  51. package/libraries/chez/common/effekt_matching.ss +0 -100
  52. package/libraries/chez/common/immutable/dequeue.effekt +0 -78
  53. package/libraries/chez/common/immutable/list.effekt +0 -643
  54. package/libraries/chez/common/immutable/option.effekt +0 -39
  55. package/libraries/chez/common/immutable/result.effekt +0 -29
  56. package/libraries/chez/common/io/args.effekt +0 -20
  57. package/libraries/chez/common/mutable/array.effekt +0 -27
  58. package/libraries/chez/common/mutable/heap.effekt +0 -12
  59. package/libraries/chez/common/test.effekt +0 -59
  60. package/libraries/chez/common/text/string.effekt +0 -46
  61. package/libraries/chez/lift/effekt.effekt +0 -217
  62. package/libraries/chez/lift/effekt.ss +0 -118
  63. package/libraries/chez/monadic/effekt.effekt +0 -218
  64. package/libraries/js/effekt.effekt +0 -284
  65. package/libraries/js/effekt_matching.js +0 -79
  66. package/libraries/js/immutable/list.effekt +0 -643
  67. package/libraries/js/immutable/option.effekt +0 -49
  68. package/libraries/js/immutable/result.effekt +0 -29
  69. package/libraries/js/io/args.effekt +0 -9
  70. package/libraries/js/io/async.effekt +0 -28
  71. package/libraries/js/io/async.js +0 -2
  72. package/libraries/js/io/file.effekt +0 -50
  73. package/libraries/js/io/file_include.js +0 -13
  74. package/libraries/js/mutable/array.effekt +0 -98
  75. package/libraries/js/mutable/heap.effekt +0 -32
  76. package/libraries/js/test.effekt +0 -59
  77. package/libraries/js/text/string.effekt +0 -64
  78. package/libraries/llvm/effekt.effekt +0 -243
  79. package/libraries/llvm/immutable/option.effekt +0 -53
  80. package/libraries/llvm/immutable/result.effekt +0 -29
  81. package/libraries/llvm/io/args.effekt +0 -24
  82. package/libraries/llvm/text/string.effekt +0 -179
  83. package/libraries/ml/effekt.effekt +0 -267
  84. package/libraries/ml/effekt.sml +0 -63
  85. package/libraries/ml/immutable/dequeue.effekt +0 -81
  86. package/libraries/ml/immutable/list.effekt +0 -674
  87. package/libraries/ml/immutable/option.effekt +0 -53
  88. package/libraries/ml/immutable/result.effekt +0 -29
  89. package/libraries/ml/internal/option.effekt +0 -18
  90. package/libraries/ml/io/args.effekt +0 -41
  91. package/libraries/ml/mutable/array.effekt +0 -43
  92. package/libraries/ml/random.effekt +0 -85
  93. package/libraries/ml/test.effekt +0 -60
  94. package/libraries/ml/text/regex.effekt +0 -107
  95. package/libraries/ml/text/string.effekt +0 -81
@@ -1,29 +0,0 @@
1
- import immutable/option
2
-
3
- // Results
4
- // =======
5
- // The "reification" of the Exception[E] effect.
6
- type Result[A, E] {
7
- Error(exception: E, msg: String);
8
- Success(a: A)
9
- }
10
-
11
- def result[A, E] { f: () => A / Exception[E] }: Result[A, E] = try {
12
- Success(f())
13
- } with Exception[E] {
14
- def raise(exc, msg) = Error(exc, msg)
15
- }
16
-
17
- /**
18
- * Extracts the value of a result, if available
19
- * Monadic "reflection"
20
- */
21
- def value[A, E](r: Result[A, E]): A / Exception[E] = r match {
22
- case Success(a) => a
23
- case Error(exc, msg) => do raise(exc, msg)
24
- }
25
-
26
- def toOption[A, E](r: Result[A, E]): Option[A] = r match {
27
- case Success(a) => Some(a)
28
- case Error(exc, msg) => None()
29
- }
@@ -1,18 +0,0 @@
1
- module internal/option
2
-
3
- import effekt
4
- import immutable/option
5
-
6
- extern type MLOption[T]
7
-
8
- extern pure def isDefined[T](opt: MLOption[T]): Boolean =
9
- "Option.isSome ${opt}"
10
-
11
- def isEmpty[T](opt: MLOption[T]): Boolean = not(opt.isDefined())
12
-
13
- extern pure def force[T](opt: MLOption[T]): T =
14
- "Option.valOf ${opt}"
15
-
16
- def toOption[T](opt: MLOption[T]): Option[T] = {
17
- if (isDefined(opt)) Some(force(opt)) else None()
18
- }
@@ -1,41 +0,0 @@
1
- module io/args
2
-
3
- import effekt
4
- import internal/option
5
- import immutable/option
6
- import immutable/list
7
-
8
-
9
- // ================================================
10
- //
11
- // Conceptual Public Functions:
12
- // - commandLineArgs(): List[String]
13
- //
14
- // ================================================
15
-
16
-
17
- // ml Ref of ml list
18
- extern type Args
19
-
20
- // Works like an iterator
21
- extern io def nativeArgs(): Args =
22
- "ref (CommandLine.arguments ())"
23
-
24
- extern """
25
- fun nextArgument a =
26
- case !a of
27
- [] => NONE |
28
- x :: xs => (a := xs; SOME x);
29
- """
30
-
31
- // consumes the next arg if present
32
- extern io def nativeNext(a: Args): MLOption[String] =
33
- "nextArgument ${a}"
34
-
35
- def commandLineArgs(): List[String] = {
36
- def argsToRevList(a: Args, acc: List[String]): List[String] = toOption(nativeNext(a)) match {
37
- case None() => acc
38
- case Some(v) => argsToRevList(a, Cons(v, acc))
39
- }
40
- reverse(argsToRevList(nativeArgs(), Nil()))
41
- }
@@ -1,43 +0,0 @@
1
- module mutable/array
2
-
3
- import immutable/option
4
-
5
- // A mutable array, backed by a sml array.
6
- extern type Array[T]
7
-
8
- extern pure def emptyArray[T](): Array[T] =
9
- "Array.fromList []"
10
-
11
- extern pure def array[T](initialSize: Int, init: T): Array[T] =
12
- "Array.array (${initialSize}, ${init})"
13
-
14
- def get[T](arr: Array[T], index: Int): Option[T] = {
15
- val len = size(arr);
16
- if (index < 0 || len <= index) None()
17
- else Some(unsafeGet(arr, index))
18
- }
19
-
20
- extern pure def size[T](arr: Array[T]): Int =
21
- "Array.length ${arr}"
22
-
23
- extern pure def unsafeGet[T](arr: Array[T], index: Int): T =
24
- "Array.sub (${arr}, ${index})"
25
-
26
- def put[T](arr: Array[T], index: Int, value: T): Unit =
27
- if (index < 0 || size(arr) <= index) ()
28
- else unsafeput(arr, index, value)
29
-
30
- extern io def unsafeput[T](arr: Array[T], index: Int, value: T): Unit =
31
- "Array.update (${arr}, ${index}, ${value})"
32
-
33
- def copy[T](arr: Array[T]): Array[T] =
34
- get(arr, 0) match {
35
- case None() => emptyArray()
36
- case Some(first) =>
37
- val dst = array(size(arr), first)
38
- copyInto(arr, dst);
39
- dst
40
- }
41
-
42
- extern pure def copyInto[T](src: Array[T], dst: Array[T]): Unit =
43
- "Array.copy {src = ${src}, dst = ${dst}, di = 0}"
@@ -1,85 +0,0 @@
1
- module random
2
-
3
- /**
4
- * Imperative Random Numbers
5
- * -------------------------
6
- * The following are simple bindings for the following SML/NJ module:
7
- * https://www.smlnj.org/doc/smlnj-lib/Util/str-Random.html
8
- *
9
- * They are not supposed to be used directly, but only via the
10
- * effect [[Random]], below.
11
- */
12
- extern type RNG // = int * int
13
- extern io def seed(n: Int, m: Int): RNG = "Random.rand (${n}, ${m})"
14
- extern pure def toString(s: RNG): String = "Random.toString ${s}"
15
-
16
- extern io def int(s: RNG): Int = "Random.randInt ${s}"
17
- extern io def int(s: RNG, from: Int, to: Int): Int = "Random.randRange (${from}, ${to}) ${s}"
18
- extern io def double(s: RNG): Double = "Random.randReal ${s}"
19
-
20
-
21
- /**
22
- * Functional Random Numbers
23
- * -------------------------
24
- * The following are simple bindings for the following SML/NJ module:
25
- * https://www.smlnj.org/doc/smlnj-lib/Util/str-Rand.html
26
- *
27
- * They are not supposed to be used directly, but only via the
28
- * effect [[Random]], below.
29
- */
30
- extern type PseudoRNG
31
- extern pure def random(s: PseudoRNG): PseudoRNG =
32
- "Rand.random ${s}"
33
- extern pure def range(s: PseudoRNG, n: Int, m: Int): Int =
34
- "Rand.range (${n}, ${m}) ${s}"
35
- extern pure def norm(s: PseudoRNG): Double =
36
- "Rand.norm ${s}"
37
-
38
- // converting two integers into a word that is between randMin and randMax is completely made up
39
- extern pure def pseudo(n: Int, m: Int): PseudoRNG =
40
- "Word.fromInt ((Word.toInt Rand.randMin) + ((abs (${n} * ${m})) mod (Word.toInt Rand.randMax)))"
41
-
42
-
43
-
44
- // "Public" API
45
- // ------------
46
-
47
- /**
48
- * A random number generator.
49
- *
50
- * Supposed to be used as an effect: `do randomInt(0, 10)`.
51
- * There are two canonical implementations as effect handlers (see below).
52
- */
53
- interface Random {
54
- // returns a random integer between `from` and `to`
55
- def randomInt(from: Int, to: Int): Int
56
- // returns a random double between 0.0 and 1.0
57
- def randomDouble(): Double
58
- }
59
-
60
- /**
61
- * Imperative random numbers. Does not perform backtracking.
62
- */
63
- def withRandom[R](n: Int, m: Int) { prog: => R / Random } = {
64
- // should be second class, is mutated...
65
- val rng = seed(n, m)
66
- try { prog() }
67
- with Random {
68
- def randomInt(from, to) = resume(rng.int(from, to))
69
- def randomDouble() = resume(rng.double())
70
- }
71
- }
72
-
73
- /**
74
- * Functional, pseudo random numbers. According to SMLNJ docs it is faster than the imperative version
75
- */
76
- def withPseudoRandom[R](n: Int, m: Int) { prog: => R / Random } = {
77
- // should be second class, is mutated...
78
- var rng = pseudo(n, m)
79
- def next() = rng = random(rng);
80
- try { prog() }
81
- with Random {
82
- def randomInt(from, to) = { next(); resume(rng.range(from, to)) }
83
- def randomDouble() = { next(); resume(rng.norm()) }
84
- }
85
- }
@@ -1,60 +0,0 @@
1
- import text/string
2
-
3
- interface Assertion {
4
- def assert(condition: Boolean, msg: String): Unit
5
- }
6
-
7
- def assertTrue(condition: Boolean, msg: String) =
8
- do assert(condition, msg)
9
-
10
- def assertTrue(condition: Boolean) =
11
- do assert(condition, "Assertion failed")
12
-
13
- def assertFalse(condition: Boolean, msg: String) =
14
- do assert(not(condition), msg)
15
-
16
- def assertFalse(condition: Boolean) =
17
- do assert(not(condition), "Assertion failed")
18
-
19
- def assertEqual[A](obtained: A, expected: A, msg: String) =
20
- do assert(obtained == expected, msg)
21
-
22
- // Note: every other backend uses a generic `show` instead
23
- def assertEqual[A](obtained: A, expected: A) { show : A => String } =
24
- do assert(obtained == expected, "Obtained: " ++ show(obtained) ++ "\n but expected:" ++ show(expected))
25
-
26
- interface Test {
27
- def success(name: String): Unit
28
- def failure(name: String, msg: String): Unit
29
- }
30
-
31
- def test(name: String) { body: => Unit / Assertion } =
32
- try { body(); do success(name) } with Assertion {
33
- def assert(condition, msg) = if (condition) resume(()) else do failure(name, msg)
34
- }
35
-
36
- def suite(name: String) { body: => Unit / Test }: Boolean = {
37
- println("Running suite: " ++ name);
38
- var failed = 0
39
- var passed = 0
40
-
41
- try { body() } with Test {
42
- def success(name) = {
43
- passed = passed + 1
44
- println(ANSI_GREEN ++ "+ " ++ name ++ "" ++ ANSI_RESET);
45
- resume(())
46
- }
47
- def failure(name, msg) = {
48
- failed = failed + 1
49
- println(ANSI_RED ++ "- (FAIL) " ++ name ++ "\n " ++ msg ++ ANSI_RESET);
50
- resume(())
51
- }
52
- }
53
- if (failed > 0) {
54
- println(ANSI_RED ++ "Some tests failed (" ++ passed.show ++ " passed, " ++ failed.show ++ " failed)" ++ ANSI_RESET)
55
- false
56
- } else {
57
- println(ANSI_GREEN ++ "All tests passed (" ++ passed.show ++ " passed)" ++ ANSI_RESET)
58
- true
59
- }
60
- }
@@ -1,107 +0,0 @@
1
- module text/regex
2
-
3
- extern type MLList[Elem] // = 'elem list
4
- extern pure def isEmpty[A](l: MLList[A]): Boolean = "null ${l}"
5
- extern pure def head[A](l: MLList[A]): A = "hd ${l}"
6
- extern pure def tail[A](l: MLList[A]): MLList[A] = "tl ${l}"
7
-
8
- def toList[A](l: MLList[A]): List[A] =
9
- if (l.isEmpty) Nil() else Cons(l.head, toList(l.tail))
10
-
11
- extern type Char // TODO move to text/string
12
- type Chars = MLList[Char]
13
-
14
-
15
- extern pure def chars(str: String): Chars = "String.explode ${str}"
16
- extern pure def toString(chars: Chars): String = "String.implode ${chars}"
17
-
18
- extern """
19
-
20
- (** The RegExp module is created by choosing a parser (P) and an engine (E)
21
- * for regular expressions.
22
- *
23
- * There is no big choice for the parser, since only Awk syntax is supported.
24
- * For the regular expression engine, we choose Ken Thompson's algorighm.
25
- *
26
- * Also see:
27
- * <https://stackoverflow.com/questions/35462919/how-to-use-regex-in-smlnj>
28
- * <https://www.smlnj.org/doc/smlnj-lib/RegExp/fun-RegExpFn.html>
29
- *)
30
- structure RegExp = RegExpFn(
31
- structure P = AwkSyntax
32
- structure E = ThompsonEngine
33
- (* structure E = BackTrackEngine *)
34
- (* structure E = DfaEngine *)
35
- )
36
- """
37
-
38
- // The type of regular expressions (ML representation)
39
- extern type Regex
40
-
41
- record Match(matched: String)
42
-
43
- // TODO handle CannotParse and CannotCompile ml exceptions.
44
- extern pure def regex(regexString: String): Regex =
45
- "RegExp.compileString ${regexString}"
46
-
47
-
48
- // A stream of elements of type Elem, read from a source of type Source
49
- extern type MLStream[Elem, Source] // = ('elem, 'source) StringCvt.reader
50
-
51
- // Internal ml type that represents matches
52
- // <https://www.smlnj.org/doc/smlnj-lib/RegExp/str-MatchTree.html>
53
- extern type MLMatchResult // = match * char list
54
-
55
- extern """
56
- type regex_match = {len: int, pos: char list} MatchTree.match_tree;
57
- fun matchedString (match : regex_match * char list) =
58
- let val res = MatchTree.root (#1 match)
59
- in String.implode (List.take (#pos res, #len res)) end;
60
-
61
- fun remainderChars (match : regex_match * char list) =
62
- let val res = MatchTree.root (#1 match)
63
- in List.drop (#pos res, #len res) end;
64
-
65
- (** The remainder is just a draft and doesn't work yet...) *)
66
-
67
- (** MatchTree -> string list **)
68
- fun allMatched (matchtree: regex_match) =
69
- MatchTree.foldl (fn (m, b) => (String.implode (List.take (#pos m, #len m))) :: b) nil matchtree
70
- fun allBut str = RegExp.compileString ("[^" ^ str ^ "]+");
71
-
72
- fun unsafeSplit str sep =
73
- case (RegExp.find (allBut str) List.getItem (String.explode str)) of
74
- NONE => nil
75
- | SOME v => allMatched (#1 v);
76
- """
77
-
78
- extern pure def getMatch(result: MLMatchResult): String =
79
- "matchedString ${result}"
80
- extern pure def getRemainder(result: MLMatchResult): Chars =
81
- "remainderChars ${result}"
82
-
83
- extern pure def unsafeSplit(str: String, ch: Char): MLList[String] =
84
- "String.fields (fn c => c = ${ch}) ${str}"
85
-
86
- extern pure def unsafeMatchPrefix(r: Regex, str: Chars): MLOption[MLMatchResult] =
87
- "RegExp.prefix ${r} List.getItem ${str}"
88
-
89
- extern pure def unsafeSplit(str: String, sep: String): MLList[String] =
90
- "unsafeSplit ${str} ${sep}"
91
-
92
- extern """
93
- val NEWLINE_CHAR = #"\n";
94
- """
95
-
96
- extern pure def unsafeLines(str: String): MLList[String] =
97
- "String.fields (fn c => c = NEWLINE_CHAR) ${str}"
98
-
99
- def lines(str: String): List[String] = unsafeLines(str).toList
100
-
101
- def split(str: String, sep: String): List[String] = unsafeSplit(str, sep).toList
102
-
103
- def exec(reg: Regex, str: String): Option[Match] = {
104
- val matched = reg.unsafeMatchPrefix(str.chars)
105
- if (matched.isDefined) { Some(Match(matched.force.getMatch())) }
106
- else { None() }
107
- }
@@ -1,81 +0,0 @@
1
- module text/string
2
-
3
- import effekt
4
- import immutable/option
5
- import internal/option
6
-
7
- // For more information on the sml string type:
8
- // https://smlfamily.github.io/Basis/string.html#String:STR:SPEC
9
-
10
- def charAt(str: String, index: Int): Option[String] =
11
- if (index < 0 || length(str) <= index)
12
- Some(unsafeCharAt(str, index))
13
- else None()
14
-
15
- extern pure def length(str: String): Int =
16
- "String.size ${str}"
17
-
18
- extern pure def startsWith(str: String, prefix: String): Boolean =
19
- "String.isPrefix ${prefix} ${str}"
20
-
21
- extern pure def endsWith(str: String, suffix: String): Boolean =
22
- "String.isSuffix ${suffix} ${str}"
23
-
24
- // extern pure def repeat(str: String, n: Int): String =
25
- // "???"
26
-
27
- def substring(str: String, from: Int, to: Int): String = {
28
- def clamp(lower: Int, x: Int, upper: Int) = max(lower, min(x, upper))
29
-
30
- val len = str.length
31
- val clampedTo = clamp(0, to, len)
32
- val clampedFrom = clamp(0, from, to)
33
-
34
- val substringLength = max(0, clampedTo - clampedFrom)
35
- str.unsafeSubstring(clampedFrom, substringLength)
36
- }
37
-
38
- def substring(str: String, from: Int): String =
39
- str.substring(from, str.length)
40
-
41
- extern pure def unsafeSubstring(str: String, from: Int, len: Int): String =
42
- "String.extract (${str}, ${from}, SOME ${len})"
43
-
44
- // extern pure def split(str: String, sep: String): Array[String] =
45
- // "Array.fromList (map (String.str) (String.explode str))"
46
-
47
- // extern pure def trim(str: String): String =
48
- // "???"
49
-
50
- // also accepts sml style `~2` for unary minus along with `+2` and `-2`
51
- extern pure def internalStringToInt(str: String): MLOption[Int] =
52
- "Int.fromString ${str}"
53
-
54
- def toInt(str: String): Option[Int] = toOption(internalStringToInt(str))
55
-
56
- extern pure def unsafeCharAt(str: String, n: Int): String =
57
- "String.sub (${str}, ${n})"
58
-
59
- def indexOf(str: String, sub: String): Option[Int] = {
60
- def loop(str: String, sub: String, index: Int): Int = {
61
- if (index >= str.length) { -1 }
62
- else if (str.substring(index).startsWith(sub)) { index }
63
- else { loop(str, sub, index + 1) }
64
- }
65
- val index = loop(str, sub, 0)
66
- if (index == -1) { None() } else { Some(index) }
67
- }
68
-
69
- def lastIndexOf(str: String, sub: String): Option[Int] = {
70
- def loop(str: String, sub: String, index: Int): Int = {
71
- if (index < 0) { -1 }
72
- else if (str.substring(index).startsWith(sub)) { index }
73
- else { loop(str, sub, index - 1) }
74
- }
75
- val index = loop(str, sub, str.length)
76
- if (index == -1) { None() } else { Some(index) }
77
- }
78
-
79
- val ANSI_GREEN = "\u001b[32m"
80
- val ANSI_RED = "\u001b[31m"
81
- val ANSI_RESET = "\u001b[0m"