@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.
- package/README.md +6 -18
- package/bin/effekt +0 -0
- package/libraries/common/args.effekt +0 -27
- package/libraries/common/array.effekt +34 -63
- package/libraries/common/bench.effekt +40 -22
- package/libraries/common/buffer.effekt +8 -20
- package/libraries/common/bytes.effekt +5 -15
- package/libraries/common/dequeue.effekt +5 -5
- package/libraries/common/effekt.effekt +51 -92
- package/libraries/common/exception.effekt +0 -1
- package/libraries/common/io/console.effekt +30 -36
- package/libraries/common/io/error.effekt +131 -30
- package/libraries/common/io/filesystem.effekt +262 -0
- package/libraries/common/io/network.effekt +30 -54
- package/libraries/common/io/time.effekt +9 -12
- package/libraries/common/io.effekt +54 -124
- package/libraries/common/list.effekt +345 -327
- package/libraries/common/process.effekt +0 -1
- package/libraries/common/queue.effekt +1 -3
- package/libraries/common/ref.effekt +11 -24
- package/libraries/common/result.effekt +6 -14
- package/libraries/common/seq.effekt +28 -49
- package/libraries/common/string/tty.effekt +66 -0
- package/libraries/common/string.effekt +7 -49
- package/libraries/common/test.effekt +96 -34
- package/libraries/js/unsafe/cont.effekt +1 -1
- package/libraries/llvm/io.c +258 -378
- package/libraries/llvm/main.c +3 -0
- package/libraries/llvm/rts.ll +57 -38
- package/libraries/llvm/types.c +10 -1
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
- package/licenses/mit license - mit-license.html +21 -20
- package/licenses/the bsd license - bsd-license.html +20 -21
- package/licenses/the mit license - mit.html +22 -21
- package/package.json +1 -1
- package/libraries/chez/lift/effekt.ss +0 -118
- package/libraries/common/io/files.effekt +0 -282
- package/libraries/js/io.js +0 -143
- package/libraries/llvm/io.ll +0 -19
- package/libraries/ml/effekt.sml +0 -65
- package/libraries/ml/internal/mllist.effekt +0 -9
- package/libraries/ml/internal/mloption.effekt +0 -18
- package/libraries/ml/random.effekt +0 -85
- package/libraries/ml/text/regex.effekt +0 -102
package/libraries/js/io.js
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Maps the error code to a Effekt-stable (platform independent) numeric value.
|
|
4
|
-
*
|
|
5
|
-
* Tries to use most common errno integer values, but introduces fresh values (> 200)
|
|
6
|
-
* for those without common errno values.
|
|
7
|
-
*/
|
|
8
|
-
function errnoToStableId(errorName) {
|
|
9
|
-
const errorMap = {
|
|
10
|
-
EPERM: 1,
|
|
11
|
-
ENOENT: 2,
|
|
12
|
-
ESRCH: 3,
|
|
13
|
-
EINTR: 4,
|
|
14
|
-
EIO: 5,
|
|
15
|
-
ENXIO: 6,
|
|
16
|
-
E2BIG: 7,
|
|
17
|
-
EBADF: 9,
|
|
18
|
-
EAGAIN: 11,
|
|
19
|
-
ENOMEM: 12,
|
|
20
|
-
EACCES: 13,
|
|
21
|
-
EFAULT: 14,
|
|
22
|
-
EBUSY: 16,
|
|
23
|
-
EEXIST: 17,
|
|
24
|
-
EXDEV: 18,
|
|
25
|
-
ENODEV: 19,
|
|
26
|
-
ENOTDIR: 20,
|
|
27
|
-
EISDIR: 21,
|
|
28
|
-
EINVAL: 22,
|
|
29
|
-
ENFILE: 23,
|
|
30
|
-
EMFILE: 24,
|
|
31
|
-
ENOTTY: 25,
|
|
32
|
-
ETXTBSY: 26,
|
|
33
|
-
EFBIG: 27,
|
|
34
|
-
ENOSPC: 28,
|
|
35
|
-
ESPIPE: 29,
|
|
36
|
-
EROFS: 30,
|
|
37
|
-
EMLINK: 31,
|
|
38
|
-
EPIPE: 32,
|
|
39
|
-
ERANGE: 34,
|
|
40
|
-
ENAMETOOLONG: 36,
|
|
41
|
-
ELOOP: 40,
|
|
42
|
-
EOVERFLOW: 75,
|
|
43
|
-
EFTYPE: 79,
|
|
44
|
-
EILSEQ: 84,
|
|
45
|
-
ENOTSOCK: 88,
|
|
46
|
-
EDESTADDRREQ: 89,
|
|
47
|
-
EMSGSIZE: 90,
|
|
48
|
-
EPROTOTYPE: 91,
|
|
49
|
-
ENOPROTOOPT: 92,
|
|
50
|
-
EPROTONOSUPPORT: 93,
|
|
51
|
-
ESOCKTNOSUPPORT: 94,
|
|
52
|
-
ENOTSUP: 95,
|
|
53
|
-
EAFNOSUPPORT: 97,
|
|
54
|
-
EADDRINUSE: 98,
|
|
55
|
-
EADDRNOTAVAIL: 99,
|
|
56
|
-
ENETDOWN: 100,
|
|
57
|
-
ENETUNREACH: 101,
|
|
58
|
-
ECONNABORTED: 103,
|
|
59
|
-
ECONNRESET: 104,
|
|
60
|
-
ENOBUFS: 105,
|
|
61
|
-
EISCONN: 106,
|
|
62
|
-
ENOTCONN: 107,
|
|
63
|
-
ETIMEDOUT: 110,
|
|
64
|
-
ECONNREFUSED: 111,
|
|
65
|
-
EHOSTUNREACH: 113,
|
|
66
|
-
EALREADY: 114,
|
|
67
|
-
ECANCELED: 125,
|
|
68
|
-
EAI_ADDRFAMILY: 200,
|
|
69
|
-
EAI_AGAIN: 201,
|
|
70
|
-
EAI_BADFLAGS: 202,
|
|
71
|
-
EAI_BADHINTS: 203,
|
|
72
|
-
EAI_CANCELED: 204,
|
|
73
|
-
EAI_FAIL: 205,
|
|
74
|
-
EAI_FAMILY: 206,
|
|
75
|
-
EAI_MEMORY: 207,
|
|
76
|
-
EAI_NODATA: 208,
|
|
77
|
-
EAI_NONAME: 209,
|
|
78
|
-
EAI_OVERFLOW: 210,
|
|
79
|
-
EAI_PROTOCOL: 211,
|
|
80
|
-
EAI_SERVICE: 212,
|
|
81
|
-
EAI_SOCKTYPE: 213,
|
|
82
|
-
ECHARSET: 215,
|
|
83
|
-
ENONET: 216,
|
|
84
|
-
UNKNOWN: 217,
|
|
85
|
-
EOF: 218,
|
|
86
|
-
EUNATCH: 219,
|
|
87
|
-
ESHUTDOWN: 220
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
return errorMap[errorName] || -1; // Default to -1 for unknown error names
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function openFile(path, mode, onSuccess, onFailure) {
|
|
94
|
-
fs.open(path, mode,
|
|
95
|
-
(err, fd) => {
|
|
96
|
-
if (!!err) {
|
|
97
|
-
console.error(err)
|
|
98
|
-
return onFailure(errnoToStableId(err.code)).run();
|
|
99
|
-
} else {
|
|
100
|
-
return onSuccess(fd).run();
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
return $effekt.unit;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function readFile(fd, buffer, offset, onSuccess, onFailure) {
|
|
107
|
-
let position = offset === -1 ? null : offset;
|
|
108
|
-
fs.read(fd, toBuffer(buffer), 0, buffer.length, position,
|
|
109
|
-
(err, bytesRead) => {
|
|
110
|
-
if (!!err) {
|
|
111
|
-
return onFailure(errnoToStableId(err.code)).run()
|
|
112
|
-
} else {
|
|
113
|
-
return onSuccess(bytesRead).run()
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
return $effekt.unit;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* @see {https://nodejs.org/api/fs.html#fswritefd-buffer-offset-length-position-callback
|
|
121
|
-
*/
|
|
122
|
-
function writeFile(fd, buffer, offset, onSuccess, onFailure) {
|
|
123
|
-
let position = offset === -1 ? null : offset;
|
|
124
|
-
fs.write(fd, toBuffer(buffer), 0, buffer.length, position,
|
|
125
|
-
(err, bytesWritten) => {
|
|
126
|
-
if (!!err) {
|
|
127
|
-
return onFailure(errnoToStableId(err.code)).run()
|
|
128
|
-
} else {
|
|
129
|
-
return onSuccess(bytesWritten).run()
|
|
130
|
-
}
|
|
131
|
-
})
|
|
132
|
-
return $effekt.unit;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Nodejs file operations expect buffers, but we represent buffers as typed arrays.
|
|
139
|
-
* This function converts between the two without copying.
|
|
140
|
-
*/
|
|
141
|
-
function toBuffer(buffer) {
|
|
142
|
-
return Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
143
|
-
}
|
package/libraries/llvm/io.ll
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
declare i64 @uv_error_to_errno(i64)
|
|
2
|
-
declare ptr @uv_strerror(i32)
|
|
3
|
-
|
|
4
|
-
declare ptr @uv_default_loop()
|
|
5
|
-
declare i32 @uv_run(ptr, i32)
|
|
6
|
-
declare void @uv_stop(ptr)
|
|
7
|
-
declare void @uv_loop_close(ptr)
|
|
8
|
-
|
|
9
|
-
; Helpers defined in C
|
|
10
|
-
declare void @c_timer_wait(i64, %Neg)
|
|
11
|
-
declare i64 @c_file_open(%Pos, %Pos, %Neg, %Neg)
|
|
12
|
-
declare void @c_file_close(%Pos)
|
|
13
|
-
declare void @c_file_read(i32, %Pos, i64, ptr, ptr)
|
|
14
|
-
declare void @c_file_write(i32, %Pos, i64, ptr, ptr)
|
|
15
|
-
declare %Pos @c_filedescriptor_show(%Pos)
|
|
16
|
-
|
|
17
|
-
declare %Pos @c_promise_make()
|
|
18
|
-
declare void @c_promise_resolve(%Pos, %Pos)
|
|
19
|
-
declare void @c_promise_await(%Pos, %Neg)
|
package/libraries/ml/effekt.sml
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
(* EVIDENCE *)
|
|
2
|
-
fun lift m k1 k2 = m (fn a => k1 a k2);
|
|
3
|
-
fun nested ev1 ev2 m = ev1 (ev2 m);
|
|
4
|
-
fun here x = x;
|
|
5
|
-
|
|
6
|
-
(* REGIONS *)
|
|
7
|
-
(* type region = ((() -> () -> ()) list) ref *)
|
|
8
|
-
fun newRegion () = ref nil
|
|
9
|
-
fun backup cell = fn () => let val oldState = !cell in fn () => cell := oldState end
|
|
10
|
-
fun fresh r init = let val cell = ref init in (r := (backup cell) :: (!r); cell) end
|
|
11
|
-
fun withRegion body =
|
|
12
|
-
let val r = newRegion()
|
|
13
|
-
fun lift m k = let val fields = map (fn f => f()) (!r) in
|
|
14
|
-
m (fn a => (map (fn f => f()) fields; k a)) end
|
|
15
|
-
in body lift r end
|
|
16
|
-
|
|
17
|
-
(* SHOW INSTANCES *)
|
|
18
|
-
fun show'int x =
|
|
19
|
-
let val s = (Int.toString x) in
|
|
20
|
-
case String.sub (s, 0) of
|
|
21
|
-
#"~" => "-" ^ String.extract (s, 1, NONE)
|
|
22
|
-
| _ => s
|
|
23
|
-
end;
|
|
24
|
-
|
|
25
|
-
(*
|
|
26
|
-
To align with the js backend inf and nan is rewritten
|
|
27
|
-
- `nan` -> `NaN`
|
|
28
|
-
- `inf` -> `Infinity`
|
|
29
|
-
- `~2.1` -> `-2.1`
|
|
30
|
-
They do still disagree on the truncating of `2.0` to `2` (ml does not).
|
|
31
|
-
*)
|
|
32
|
-
fun show'real x =
|
|
33
|
-
let val s = (Real.toString x) in
|
|
34
|
-
case s of
|
|
35
|
-
"nan" => "NaN"
|
|
36
|
-
| "inf" => "Infinity"
|
|
37
|
-
| _ => case String.sub (s, 0) of
|
|
38
|
-
#"~" => "-" ^ String.extract (s, 1, NONE)
|
|
39
|
-
| _ => s
|
|
40
|
-
end;
|
|
41
|
-
|
|
42
|
-
fun show'unit x = ""
|
|
43
|
-
|
|
44
|
-
fun show'bool x = Bool.toString x
|
|
45
|
-
|
|
46
|
-
fun show'string x = x
|
|
47
|
-
|
|
48
|
-
(* TIMING *)
|
|
49
|
-
val mlStartTime = Time.toMilliseconds (Time.now ());
|
|
50
|
-
|
|
51
|
-
(* RANDOM *)
|
|
52
|
-
fun mlRandomReal () =
|
|
53
|
-
let
|
|
54
|
-
val r = MLton.Random.rand ();
|
|
55
|
-
val rreal = MLton.Real.fromWord r;
|
|
56
|
-
val wsize = Real.fromInt Word.wordSize;
|
|
57
|
-
fun shiftRight r shift = r / (Math.pow(2.0, shift))
|
|
58
|
-
in
|
|
59
|
-
shiftRight rreal wsize
|
|
60
|
-
end;
|
|
61
|
-
|
|
62
|
-
(* HOLES *)
|
|
63
|
-
exception Hole
|
|
64
|
-
|
|
65
|
-
exception Absurd
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
module internal/mllist
|
|
2
|
-
|
|
3
|
-
extern type MLList[Elem] // = 'elem list
|
|
4
|
-
extern pure def isEmpty[A](l: MLList[A]): Bool = ml "null ${l}"
|
|
5
|
-
extern pure def head[A](l: MLList[A]): A = ml "hd ${l}"
|
|
6
|
-
extern pure def tail[A](l: MLList[A]): MLList[A] = ml "tl ${l}"
|
|
7
|
-
|
|
8
|
-
def toList[A](l: MLList[A]): List[A] =
|
|
9
|
-
if (l.isEmpty) Nil() else Cons(l.head, toList(l.tail))
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
module internal/mloption
|
|
2
|
-
|
|
3
|
-
import effekt
|
|
4
|
-
import option
|
|
5
|
-
|
|
6
|
-
extern type MLOption[T]
|
|
7
|
-
|
|
8
|
-
extern pure def isDefined[T](opt: MLOption[T]): Bool =
|
|
9
|
-
ml "Option.isSome ${opt}"
|
|
10
|
-
|
|
11
|
-
def isEmpty[T](opt: MLOption[T]): Bool = not(opt.isDefined())
|
|
12
|
-
|
|
13
|
-
extern pure def force[T](opt: MLOption[T]): T =
|
|
14
|
-
ml "Option.valOf ${opt}"
|
|
15
|
-
|
|
16
|
-
def toOption[T](opt: MLOption[T]): Option[T] = {
|
|
17
|
-
if (isDefined(opt)) Some(force(opt)) else None()
|
|
18
|
-
}
|
|
@@ -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 = ml "Random.rand (${n}, ${m})"
|
|
14
|
-
extern pure def toString(s: RNG): String = ml "Random.toString ${s}"
|
|
15
|
-
|
|
16
|
-
extern io def int(s: RNG): Int = ml "Random.randInt ${s}"
|
|
17
|
-
extern io def int(s: RNG, from: Int, to: Int): Int = ml "Random.randRange (${from}, ${to}) ${s}"
|
|
18
|
-
extern io def double(s: RNG): Double = ml "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
|
-
ml "Rand.random ${s}"
|
|
33
|
-
extern pure def range(s: PseudoRNG, n: Int, m: Int): Int =
|
|
34
|
-
ml "Rand.range (${n}, ${m}) ${s}"
|
|
35
|
-
extern pure def norm(s: PseudoRNG): Double =
|
|
36
|
-
ml "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
|
-
ml "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,102 +0,0 @@
|
|
|
1
|
-
module text/regex
|
|
2
|
-
|
|
3
|
-
import internal/mllist
|
|
4
|
-
import internal/mloption
|
|
5
|
-
|
|
6
|
-
extern type Char // TODO move to text/string
|
|
7
|
-
type Chars = MLList[Char]
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
extern pure def chars(str: String): Chars = ml "String.explode ${str}"
|
|
11
|
-
extern pure def toString(chars: Chars): String = ml "String.implode ${chars}"
|
|
12
|
-
|
|
13
|
-
extern ml """
|
|
14
|
-
|
|
15
|
-
(** The RegExp module is created by choosing a parser (P) and an engine (E)
|
|
16
|
-
* for regular expressions.
|
|
17
|
-
*
|
|
18
|
-
* There is no big choice for the parser, since only Awk syntax is supported.
|
|
19
|
-
* For the regular expression engine, we choose Ken Thompson's algorighm.
|
|
20
|
-
*
|
|
21
|
-
* Also see:
|
|
22
|
-
* <https://stackoverflow.com/questions/35462919/how-to-use-regex-in-smlnj>
|
|
23
|
-
* <https://www.smlnj.org/doc/smlnj-lib/RegExp/fun-RegExpFn.html>
|
|
24
|
-
*)
|
|
25
|
-
structure RegExp = RegExpFn(
|
|
26
|
-
structure P = AwkSyntax
|
|
27
|
-
structure E = ThompsonEngine
|
|
28
|
-
(* structure E = BackTrackEngine *)
|
|
29
|
-
(* structure E = DfaEngine *)
|
|
30
|
-
)
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
// The type of regular expressions (ML representation)
|
|
34
|
-
extern type Regex
|
|
35
|
-
|
|
36
|
-
record Match(matched: String)
|
|
37
|
-
|
|
38
|
-
// TODO handle CannotParse and CannotCompile ml exceptions.
|
|
39
|
-
extern pure def regex(regexString: String): Regex =
|
|
40
|
-
ml "RegExp.compileString ${regexString}"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// A stream of elements of type Elem, read from a source of type Source
|
|
44
|
-
extern type MLStream[Elem, Source] // = ('elem, 'source) StringCvt.reader
|
|
45
|
-
|
|
46
|
-
// Internal ml type that represents matches
|
|
47
|
-
// <https://www.smlnj.org/doc/smlnj-lib/RegExp/str-MatchTree.html>
|
|
48
|
-
extern type MLMatchResult // = match * char list
|
|
49
|
-
|
|
50
|
-
extern ml """
|
|
51
|
-
type regex_match = {len: int, pos: char list} MatchTree.match_tree;
|
|
52
|
-
fun matchedString (match : regex_match * char list) =
|
|
53
|
-
let val res = MatchTree.root (#1 match)
|
|
54
|
-
in String.implode (List.take (#pos res, #len res)) end;
|
|
55
|
-
|
|
56
|
-
fun remainderChars (match : regex_match * char list) =
|
|
57
|
-
let val res = MatchTree.root (#1 match)
|
|
58
|
-
in List.drop (#pos res, #len res) end;
|
|
59
|
-
|
|
60
|
-
(** The remainder is just a draft and doesn't work yet...) *)
|
|
61
|
-
|
|
62
|
-
(** MatchTree -> string list **)
|
|
63
|
-
fun allMatched (matchtree: regex_match) =
|
|
64
|
-
MatchTree.foldl (fn (m, b) => (String.implode (List.take (#pos m, #len m))) :: b) nil matchtree
|
|
65
|
-
fun allBut str = RegExp.compileString ("[^" ^ str ^ "]+");
|
|
66
|
-
|
|
67
|
-
fun unsafeSplit str sep =
|
|
68
|
-
case (RegExp.find (allBut str) List.getItem (String.explode str)) of
|
|
69
|
-
NONE => nil
|
|
70
|
-
| SOME v => allMatched (#1 v);
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
extern pure def getMatch(result: MLMatchResult): String =
|
|
74
|
-
ml "matchedString ${result}"
|
|
75
|
-
extern pure def getRemainder(result: MLMatchResult): Chars =
|
|
76
|
-
ml "remainderChars ${result}"
|
|
77
|
-
|
|
78
|
-
extern pure def unsafeSplit(str: String, ch: Char): MLList[String] =
|
|
79
|
-
ml "String.fields (fn c => c = ${ch}) ${str}"
|
|
80
|
-
|
|
81
|
-
extern pure def unsafeMatchPrefix(r: Regex, str: Chars): MLOption[MLMatchResult] =
|
|
82
|
-
ml "RegExp.prefix ${r} List.getItem ${str}"
|
|
83
|
-
|
|
84
|
-
extern pure def unsafeSplit(str: String, sep: String): MLList[String] =
|
|
85
|
-
ml "unsafeSplit ${str} ${sep}"
|
|
86
|
-
|
|
87
|
-
extern ml """
|
|
88
|
-
val NEWLINE_CHAR = #"\n";
|
|
89
|
-
"""
|
|
90
|
-
|
|
91
|
-
extern pure def unsafeLines(str: String): MLList[String] =
|
|
92
|
-
ml "String.fields (fn c => c = NEWLINE_CHAR) ${str}"
|
|
93
|
-
|
|
94
|
-
def lines(str: String): List[String] = unsafeLines(str).toList
|
|
95
|
-
|
|
96
|
-
def split(str: String, sep: String): List[String] = unsafeSplit(str, sep).toList
|
|
97
|
-
|
|
98
|
-
def exec(reg: Regex, str: String): Option[Match] = {
|
|
99
|
-
val matched = reg.unsafeMatchPrefix(str.chars)
|
|
100
|
-
if (matched.isDefined) { Some(Match(matched.force.getMatch())) }
|
|
101
|
-
else { None() }
|
|
102
|
-
}
|