@effekt-lang/effekt 0.2.1 → 0.3.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/LICENSE +21 -0
- package/README.md +36 -0
- package/bin/effekt +0 -0
- package/bin/effekt.sh +2 -0
- package/libraries/chez/THIRD-PARTY.txt +11 -0
- package/libraries/chez/callcc/datatype.ss +188 -0
- package/libraries/chez/callcc/effekt.ss +31 -0
- package/libraries/chez/callcc/seq.ss +44 -0
- package/libraries/chez/callcc/seq0.ss +69 -0
- package/libraries/chez/callcc/tail.ss +76 -0
- package/libraries/chez/callcc/tail0.ss +89 -0
- package/libraries/chez/common/effekt_primitives.ss +105 -0
- package/libraries/chez/common/immutable/cslist.effekt +37 -0
- package/libraries/chez/common/mutable/dict.effekt +28 -0
- package/libraries/chez/common/text/pregexp.scm +772 -0
- package/libraries/chez/common/text/regex.effekt +31 -0
- package/libraries/chez/lift/effekt.ss +118 -0
- package/libraries/chez/monadic/effekt.ss +84 -0
- package/libraries/chez/monadic/seq0.ss +76 -0
- package/libraries/common/args.effekt +95 -0
- package/libraries/common/array.effekt +225 -0
- package/libraries/common/bench.effekt +60 -0
- package/libraries/common/buffer.effekt +123 -0
- package/libraries/common/bytes.effekt +125 -0
- package/libraries/common/dequeue.effekt +92 -0
- package/libraries/common/effekt.effekt +764 -0
- package/libraries/common/exception.effekt +122 -0
- package/libraries/common/io/console.effekt +66 -0
- package/libraries/common/io/error.effekt +365 -0
- package/libraries/common/io/files.effekt +282 -0
- package/libraries/common/io/network.effekt +105 -0
- package/libraries/common/io/time.effekt +15 -0
- package/libraries/common/io.effekt +158 -0
- package/libraries/common/list.effekt +687 -0
- package/libraries/common/option.effekt +72 -0
- package/libraries/common/process.effekt +10 -0
- package/libraries/common/queue.effekt +140 -0
- package/libraries/common/ref.effekt +63 -0
- package/libraries/common/result.effekt +45 -0
- package/libraries/common/seq.effekt +914 -0
- package/libraries/common/string.effekt +395 -0
- package/libraries/common/test.effekt +98 -0
- package/libraries/js/effekt_builtins.js +57 -0
- package/libraries/js/effekt_runtime.js +385 -0
- package/libraries/js/io.js +143 -0
- package/libraries/js/mutable/map.effekt +31 -0
- package/libraries/js/text/regex.effekt +33 -0
- package/libraries/js/unsafe/cont.effekt +11 -0
- package/libraries/js/web/dom.effekt +45 -0
- package/libraries/llvm/array.c +53 -0
- package/libraries/llvm/buffer.c +286 -0
- package/libraries/llvm/forward-declare-c.ll +43 -0
- package/libraries/llvm/hole.c +11 -0
- package/libraries/llvm/io.c +566 -0
- package/libraries/llvm/io.ll +19 -0
- package/libraries/llvm/main.c +41 -0
- package/libraries/llvm/ref.c +45 -0
- package/libraries/llvm/rts.ll +761 -0
- package/libraries/llvm/sanity.c +16 -0
- package/libraries/llvm/types.c +43 -0
- package/libraries/ml/effekt.sml +65 -0
- package/libraries/ml/internal/mllist.effekt +9 -0
- package/libraries/ml/internal/mloption.effekt +18 -0
- package/libraries/ml/random.effekt +85 -0
- package/libraries/ml/text/regex.effekt +102 -0
- package/licenses/THIRD-PARTY.txt +21 -0
- package/licenses/apache-2.0 - license-2.0.txt +202 -0
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +61 -0
- package/licenses/kiama-license.txt +373 -0
- package/licenses/kiama-readme.txt +186 -0
- package/licenses/mit license - mit-license.html +1239 -0
- package/licenses/the apache software license, version 2.0 - license-2.0.txt +202 -0
- package/licenses/the bsd license - bsd-license.html +1237 -0
- package/licenses/the mit license - mit.html +1239 -0
- package/package.json +26 -18
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module text/regex
|
|
2
|
+
|
|
3
|
+
import immutable/cslist
|
|
4
|
+
|
|
5
|
+
extern include chez "pregexp.scm"
|
|
6
|
+
|
|
7
|
+
extern type Regex
|
|
8
|
+
|
|
9
|
+
record Match(matched: String, index: Int)
|
|
10
|
+
|
|
11
|
+
extern pure def regex(str: String): Regex =
|
|
12
|
+
chez "(pregexp ${str})"
|
|
13
|
+
|
|
14
|
+
def exec(reg: Regex, str: String): Option[Match] = {
|
|
15
|
+
val matched = reg.unsafeMatchString(str)
|
|
16
|
+
if (matched.isUndefined) { None() }
|
|
17
|
+
else { Some(Match(matched, reg.unsafeMatchIndex(str))) }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
extern pure def unsafeMatchIndex(reg: Regex, str: String): Int =
|
|
21
|
+
chez "(let ([m (pregexp-match-positions ${reg} ${str})]) (if m (car (car m)) #f))"
|
|
22
|
+
|
|
23
|
+
// we ignore the captures for now and only return the whole match
|
|
24
|
+
extern pure def unsafeMatchString(reg: Regex, str: String): String =
|
|
25
|
+
chez "(let ([m (pregexp-match ${reg} ${str})]) (if m (car m) #f))"
|
|
26
|
+
|
|
27
|
+
extern pure def split(reg: Regex, str: String): CSList[String] =
|
|
28
|
+
chez "(pregexp-split ${reg} ${str})"
|
|
29
|
+
|
|
30
|
+
// def split(str: String, sep: String): Array[String] =
|
|
31
|
+
// toArray(split(sep.regex, str))
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
(define-syntax delayed
|
|
2
|
+
(syntax-rules ()
|
|
3
|
+
[(_ e ...)
|
|
4
|
+
(lambda (k) (k
|
|
5
|
+
(begin e ...)))]))
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
;; EVIDENCE
|
|
9
|
+
|
|
10
|
+
(define (here x) x)
|
|
11
|
+
|
|
12
|
+
; (define-syntax lift
|
|
13
|
+
; (syntax-rules ()
|
|
14
|
+
; [(_ m)
|
|
15
|
+
; (lambda (k1)
|
|
16
|
+
; (lambda (k2)
|
|
17
|
+
; (m (lambda (a) ((k1 a) k2)))))]))
|
|
18
|
+
|
|
19
|
+
(define (lift m)
|
|
20
|
+
(lambda (k1)
|
|
21
|
+
(lambda (k2)
|
|
22
|
+
(m (lambda (a) ((k1 a) k2))))))
|
|
23
|
+
|
|
24
|
+
(define-syntax nested-helper
|
|
25
|
+
(syntax-rules ()
|
|
26
|
+
[(_ (ev) acc) (ev acc)]
|
|
27
|
+
[(_ (ev1 ev2 ...) acc)
|
|
28
|
+
(nested-helper (ev2 ...) (ev1 acc))]))
|
|
29
|
+
|
|
30
|
+
(define-syntax nested
|
|
31
|
+
(syntax-rules ()
|
|
32
|
+
[(_ ev1 ...) (lambda (m) (nested-helper (ev1 ...) m))]))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
;; HANDLING
|
|
36
|
+
|
|
37
|
+
; (define (reset m) (m (lambda (v) (lambda (k) (k v)))))
|
|
38
|
+
|
|
39
|
+
(define-syntax reset
|
|
40
|
+
(syntax-rules ()
|
|
41
|
+
[(_ m)
|
|
42
|
+
(m (lambda (v) (lambda (k) (k v))))]))
|
|
43
|
+
|
|
44
|
+
; ;; EXAMPLE
|
|
45
|
+
; ; (handle ([Fail_22 (Fail_109 () resume_120 (Nil_74))])
|
|
46
|
+
; ; (let ((tmp86_121 ((Fail_109 Fail_22))))
|
|
47
|
+
; ; (Cons_73 tmp86_121 (Nil_74))))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
; capabilities first take evidence than require selection!
|
|
51
|
+
(define-syntax handle
|
|
52
|
+
(syntax-rules ()
|
|
53
|
+
[(_ (cap1 ...) body)
|
|
54
|
+
(reset (body lift cap1 ...))]))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
(define-syntax shift
|
|
58
|
+
(syntax-rules ()
|
|
59
|
+
[(_ ev body)
|
|
60
|
+
(ev body)]))
|
|
61
|
+
|
|
62
|
+
; capabilities first take evidence than require selection!
|
|
63
|
+
(define-syntax handle-old
|
|
64
|
+
(syntax-rules ()
|
|
65
|
+
[(_ ((cap1 (op1 (arg1 ...) kid exp) ...) ...) body)
|
|
66
|
+
(reset (body lift
|
|
67
|
+
(cap1 (define-effect-op ev (arg1 ...) kid exp) ...) ...))]))
|
|
68
|
+
|
|
69
|
+
(define-syntax define-effect-op
|
|
70
|
+
(syntax-rules ()
|
|
71
|
+
[(_ ev1 (arg1 ...) kid exp ...)
|
|
72
|
+
(lambda (ev1 arg1 ...)
|
|
73
|
+
; we apply the outer evidence to the body of the operation
|
|
74
|
+
(ev1 (lambda (resume)
|
|
75
|
+
; k itself also gets evidence!
|
|
76
|
+
(let ([kid (lambda (ev v) (ev (resume v)))])
|
|
77
|
+
exp ...))))]))
|
|
78
|
+
|
|
79
|
+
(define (with-region-non-mono body)
|
|
80
|
+
(define arena (make-arena))
|
|
81
|
+
|
|
82
|
+
(define (lift m) (lambda (k)
|
|
83
|
+
; on suspend
|
|
84
|
+
(define fields (backup arena))
|
|
85
|
+
(m (lambda (a)
|
|
86
|
+
; on resume
|
|
87
|
+
(restore fields)
|
|
88
|
+
(k a)))))
|
|
89
|
+
|
|
90
|
+
(body lift arena))
|
|
91
|
+
|
|
92
|
+
(define (with-region body)
|
|
93
|
+
(define arena (make-arena))
|
|
94
|
+
|
|
95
|
+
(body arena))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
; An Arena is a pointer to a list of cells
|
|
99
|
+
(define (make-arena) (box '()))
|
|
100
|
+
|
|
101
|
+
(define (fresh arena init)
|
|
102
|
+
(let* ([cell (box init)]
|
|
103
|
+
[cells (unbox arena)])
|
|
104
|
+
(set-box! arena (cons cell cells))
|
|
105
|
+
cell))
|
|
106
|
+
|
|
107
|
+
; Backup = List<(Cell, Value)>
|
|
108
|
+
|
|
109
|
+
; Arena -> Backup
|
|
110
|
+
(define (backup arena)
|
|
111
|
+
(let ([fields (unbox arena)])
|
|
112
|
+
(map (lambda (cell) (cons cell (unbox cell))) fields)))
|
|
113
|
+
|
|
114
|
+
; Backup -> ()
|
|
115
|
+
(define (restore data)
|
|
116
|
+
(for-each (lambda (cell-data)
|
|
117
|
+
(set-box! (car cell-data) (cdr cell-data)))
|
|
118
|
+
data))
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
(define-syntax delayed
|
|
2
|
+
(syntax-rules ()
|
|
3
|
+
[(_ e)
|
|
4
|
+
(lambda (mk) (underflow e mk))]))
|
|
5
|
+
|
|
6
|
+
; Control = MetaCont -> Step
|
|
7
|
+
|
|
8
|
+
; a -> Control a
|
|
9
|
+
(define (pure v)
|
|
10
|
+
(lambda (mk) (underflow v mk)))
|
|
11
|
+
|
|
12
|
+
; Step a = (a | Control x), MetaCont x a
|
|
13
|
+
|
|
14
|
+
; (a | Control a), MetaCont -> a
|
|
15
|
+
(define (trampoline c mk)
|
|
16
|
+
(if (null? mk) c
|
|
17
|
+
(call-with-values
|
|
18
|
+
(lambda () (c mk))
|
|
19
|
+
trampoline)))
|
|
20
|
+
|
|
21
|
+
; a, MetaCont -> Step
|
|
22
|
+
(define (underflow v mk)
|
|
23
|
+
(if (null? mk) (values v mk)
|
|
24
|
+
(let* ([stack (car mk)]
|
|
25
|
+
[rest (cdr mk)]
|
|
26
|
+
[frames (Stack-frames stack)]
|
|
27
|
+
[arena (Stack-arena stack)]
|
|
28
|
+
[prompt (Stack-prompt stack)])
|
|
29
|
+
(if (null? frames) (underflow v rest)
|
|
30
|
+
(values ((car frames) v) (cons (make-Stack (cdr frames) arena prompt) rest))))))
|
|
31
|
+
|
|
32
|
+
; Control, Prompt -> Control
|
|
33
|
+
(define (reset p c)
|
|
34
|
+
(lambda (mk)
|
|
35
|
+
(c (cons (make-Stack '() (make-arena) p) mk))))
|
|
36
|
+
|
|
37
|
+
; Prompt, Body -> Control
|
|
38
|
+
(define (shift p f)
|
|
39
|
+
(lambda (mk)
|
|
40
|
+
(let-values ([(k mkrest) (splitSeq p mk)])
|
|
41
|
+
(let ([cont (lambda (a) (lambda (mk) (underflow a (appendSeq k mk))))])
|
|
42
|
+
(values (f cont) mkrest)))))
|
|
43
|
+
|
|
44
|
+
; Frame, MetaCont -> MetaCont
|
|
45
|
+
(define (push-frame f mk)
|
|
46
|
+
(if (null? mk) (error 'push-frame "Cannot push frame, meta cont ~s is empty" mk)
|
|
47
|
+
(let ([stack (car mk)]
|
|
48
|
+
[rest (cdr mk)])
|
|
49
|
+
(let ([frames (Stack-frames stack)]
|
|
50
|
+
[arena (Stack-arena stack)]
|
|
51
|
+
[prompt (Stack-prompt stack)])
|
|
52
|
+
(cons (make-Stack (cons f frames) arena prompt) rest)))))
|
|
53
|
+
|
|
54
|
+
(define-syntax then
|
|
55
|
+
(syntax-rules ()
|
|
56
|
+
[(_ m f)
|
|
57
|
+
(lambda (k) (values m (push-frame f k)))]))
|
|
58
|
+
|
|
59
|
+
(define toplevel 0)
|
|
60
|
+
|
|
61
|
+
; Control a -> a
|
|
62
|
+
(define (run c)
|
|
63
|
+
(trampoline c (cons (make-Stack '() (make-arena) toplevel) '())))
|
|
64
|
+
|
|
65
|
+
(define newPrompt (lambda () (string #\p)))
|
|
66
|
+
|
|
67
|
+
(define-syntax handle
|
|
68
|
+
(syntax-rules ()
|
|
69
|
+
[(_ ((cap1 (op1 (arg1 ...) kid exp) ...) ...) body)
|
|
70
|
+
(let ([p (newPrompt)])
|
|
71
|
+
(reset p (body
|
|
72
|
+
(cap1 (define-effect-op p (arg1 ...) kid exp) ...)
|
|
73
|
+
...)))]))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
(define-syntax define-effect-op
|
|
77
|
+
(syntax-rules ()
|
|
78
|
+
[(_ p (arg1 ...) kid exp ...)
|
|
79
|
+
(lambda (arg1 ...)
|
|
80
|
+
(shift p (lambda (kid) exp ...)))]))
|
|
81
|
+
|
|
82
|
+
; state(init) { cell => ... }
|
|
83
|
+
(define (state init body)
|
|
84
|
+
(with-region (lambda (arena) (body (fresh arena init)))))
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
; [ [f1, f2, f3, f4| fields | prompt], [f1, f2, f3, f4| fields | prompt]... ]
|
|
2
|
+
(define-record Stack (
|
|
3
|
+
[immutable frames]
|
|
4
|
+
[immutable arena]
|
|
5
|
+
[immutable prompt]))
|
|
6
|
+
|
|
7
|
+
(define-record Substack (
|
|
8
|
+
[immutable frames]
|
|
9
|
+
[immutable arena]
|
|
10
|
+
[immutable field-backup]
|
|
11
|
+
[immutable prompt]))
|
|
12
|
+
|
|
13
|
+
; MetaCont = (non-empty-list-of Stack)
|
|
14
|
+
; SubCont = (non-empty-list-of Stack)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
; An Arena is a pointer to a list of cells
|
|
18
|
+
(define (make-arena) (box '()))
|
|
19
|
+
|
|
20
|
+
(define (fresh arena init)
|
|
21
|
+
(let* ([cell (box init)]
|
|
22
|
+
[cells (unbox arena)])
|
|
23
|
+
(set-box! arena (cons cell cells))
|
|
24
|
+
cell))
|
|
25
|
+
|
|
26
|
+
; with-region { arena => ... }
|
|
27
|
+
(define (with-region body)
|
|
28
|
+
(lambda (mk)
|
|
29
|
+
(let* ([stack (car mk)]
|
|
30
|
+
[arena (Stack-arena stack)])
|
|
31
|
+
((body arena) mk))))
|
|
32
|
+
|
|
33
|
+
; Backup = List<(Cell, Value)>
|
|
34
|
+
|
|
35
|
+
; Arena -> Backup
|
|
36
|
+
(define (backup arena)
|
|
37
|
+
(let ([fields (unbox arena)])
|
|
38
|
+
(map (lambda (cell) (cons cell (unbox cell))) fields)))
|
|
39
|
+
|
|
40
|
+
; Backup -> ()
|
|
41
|
+
(define (restore data)
|
|
42
|
+
(for-each (lambda (cell-data)
|
|
43
|
+
(set-box! (car cell-data) (cdr cell-data)))
|
|
44
|
+
data))
|
|
45
|
+
|
|
46
|
+
; Prompt MetaCont -> SubCont, MetaCont
|
|
47
|
+
(define (splitSeq p seq)
|
|
48
|
+
(define (split sub s)
|
|
49
|
+
(if (null? s)
|
|
50
|
+
(error 'splitSeq "prompt ~s not found on stack" p)
|
|
51
|
+
(let* ([stack (car s)]
|
|
52
|
+
[frames (Stack-frames stack)]
|
|
53
|
+
[arena (Stack-arena stack)]
|
|
54
|
+
[prompt (Stack-prompt stack)]
|
|
55
|
+
[rest (cdr s)])
|
|
56
|
+
(define sub* (cons (make-Substack frames arena (backup arena) prompt) sub))
|
|
57
|
+
(if (not (eq? prompt p))
|
|
58
|
+
(split sub* rest)
|
|
59
|
+
(values sub* rest)))))
|
|
60
|
+
(split (list) seq))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
(define (appendSeq subcont meta)
|
|
64
|
+
(if (null? subcont)
|
|
65
|
+
meta
|
|
66
|
+
(let* ([stack (car subcont)]
|
|
67
|
+
[frames (Substack-frames stack)]
|
|
68
|
+
[arena (Substack-arena stack)]
|
|
69
|
+
[fields (Substack-field-backup stack)]
|
|
70
|
+
[prompt (Substack-prompt stack)]
|
|
71
|
+
[_ (restore fields)]
|
|
72
|
+
[rest (cdr subcont)])
|
|
73
|
+
(appendSeq rest (cons (make-Stack frames arena prompt) meta)))))
|
|
74
|
+
|
|
75
|
+
; (define ex (list (make-Stack '(1 2 3) (list (box 1)) 4) (make-Stack '(1 2 3) (list (box 2)) 3) (make-Stack '(1 2 3) (list (box 3)) 2) (make-Stack '(4 5 6) (list (box 4)) 1)))
|
|
76
|
+
; (let-values ([(cont meta) (splitSeq 2 ex)]) (appendSeq cont meta))
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module args
|
|
2
|
+
|
|
3
|
+
extern io def commandLineArgs(): List[String] =
|
|
4
|
+
js { js::commandLineArgs() }
|
|
5
|
+
chez { chez::commandLineArgs() }
|
|
6
|
+
ml { ml::commandLineArgs() }
|
|
7
|
+
llvm { llvm::commandLineArgs() }
|
|
8
|
+
|
|
9
|
+
namespace js {
|
|
10
|
+
extern type Args // = Array[String]
|
|
11
|
+
|
|
12
|
+
extern io def nativeArgs(): Args = js "process.argv.slice(1)"
|
|
13
|
+
|
|
14
|
+
extern io def argCount(args: Args): Int = js "${args}.length"
|
|
15
|
+
|
|
16
|
+
extern io def argument(args: Args, i: Int): String = js "${args}[${i}]"
|
|
17
|
+
|
|
18
|
+
def commandLineArgs(): List[String] = {
|
|
19
|
+
def toList(args: Args, start: Int, acc: List[String]): List[String] =
|
|
20
|
+
if (start < 1) { acc }
|
|
21
|
+
else args.toList(start - 1, Cons(args.argument(start), acc))
|
|
22
|
+
|
|
23
|
+
val args = nativeArgs()
|
|
24
|
+
args.toList(args.argCount - 1, Nil())
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
namespace chez {
|
|
29
|
+
extern type Args // = CSList[String]
|
|
30
|
+
|
|
31
|
+
extern io def nativeArgs(): Args =
|
|
32
|
+
chez "(cdr (command-line))"
|
|
33
|
+
|
|
34
|
+
extern pure def isEmpty(l: Args): Bool =
|
|
35
|
+
chez "(null? ${l})"
|
|
36
|
+
|
|
37
|
+
extern pure def head(l: Args): String =
|
|
38
|
+
chez "(car ${l})"
|
|
39
|
+
|
|
40
|
+
extern pure def tail(l: Args): Args =
|
|
41
|
+
chez "(cdr ${l})"
|
|
42
|
+
|
|
43
|
+
def toList(l: Args): List[String] =
|
|
44
|
+
if (l.isEmpty) Nil() else Cons(l.head, l.tail.toList)
|
|
45
|
+
|
|
46
|
+
def commandLineArgs(): List[String] = nativeArgs().toList
|
|
47
|
+
}
|
|
48
|
+
|
|
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
|
+
namespace llvm {
|
|
76
|
+
extern io def argCount(): Int =
|
|
77
|
+
llvm """
|
|
78
|
+
%c = call %Int @c_get_argc()
|
|
79
|
+
ret %Int %c
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
extern io def argument(i: Int): String =
|
|
83
|
+
llvm """
|
|
84
|
+
%s = call %Pos @c_get_arg(%Int ${i})
|
|
85
|
+
ret %Pos %s
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def commandLineArgs(): List[String] = {
|
|
89
|
+
def toList(start: Int, acc: List[String]): List[String] =
|
|
90
|
+
if (start < 1) { acc }
|
|
91
|
+
else toList(start - 1, Cons(argument(start), acc))
|
|
92
|
+
|
|
93
|
+
toList(argCount() - 1, Nil())
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
module array
|
|
2
|
+
|
|
3
|
+
import effekt
|
|
4
|
+
import exception
|
|
5
|
+
import list
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A mutable 0-indexed fixed-sized array.
|
|
9
|
+
*/
|
|
10
|
+
extern type Array[T]
|
|
11
|
+
|
|
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
|
+
*/
|
|
16
|
+
extern global def allocate[T](size: Int): Array[T] =
|
|
17
|
+
js "(new Array(${size}))"
|
|
18
|
+
chez "(make-vector ${size})" // creates an array filled with 0s on CS
|
|
19
|
+
llvm """
|
|
20
|
+
%z = call %Pos @c_array_new(%Int ${size})
|
|
21
|
+
ret %Pos %z
|
|
22
|
+
"""
|
|
23
|
+
|
|
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
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Converts a List `list` to an Array
|
|
39
|
+
*/
|
|
40
|
+
def fromList[T](list: List[T]): Array[T] = {
|
|
41
|
+
val listSize = list.size();
|
|
42
|
+
val arr = allocate(listSize);
|
|
43
|
+
|
|
44
|
+
foreachIndex(list) { (i, head) =>
|
|
45
|
+
arr.unsafeSet(i, head)
|
|
46
|
+
}
|
|
47
|
+
return arr;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Gets the length of the array in constant time.
|
|
52
|
+
*/
|
|
53
|
+
extern pure def size[T](arr: Array[T]): Int =
|
|
54
|
+
js "${arr}.length"
|
|
55
|
+
chez "(vector-length ${arr})"
|
|
56
|
+
ml "Array.length ${arr}"
|
|
57
|
+
llvm """
|
|
58
|
+
%z = call %Int @c_array_size(%Pos ${arr})
|
|
59
|
+
ret %Int %z
|
|
60
|
+
"""
|
|
61
|
+
|
|
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
|
+
*/
|
|
68
|
+
extern global def unsafeGet[T](arr: Array[T], index: Int): T =
|
|
69
|
+
js "${arr}[${index}]"
|
|
70
|
+
chez "(vector-ref ${arr} ${index})"
|
|
71
|
+
ml "Array.sub (${arr}, ${index})"
|
|
72
|
+
llvm """
|
|
73
|
+
%z = call %Pos @c_array_get(%Pos ${arr}, %Int ${index})
|
|
74
|
+
ret %Pos %z
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
extern js """
|
|
78
|
+
function array$set(arr, index, value) {
|
|
79
|
+
arr[index] = value;
|
|
80
|
+
return $effekt.unit
|
|
81
|
+
}
|
|
82
|
+
"""
|
|
83
|
+
|
|
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
|
+
*/
|
|
90
|
+
extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit =
|
|
91
|
+
js "array$set(${arr}, ${index}, ${value})"
|
|
92
|
+
chez "(begin (vector-set! ${arr} ${index} ${value}) #f)"
|
|
93
|
+
ml "Array.update (${arr}, ${index}, ${value})"
|
|
94
|
+
llvm """
|
|
95
|
+
%z = call %Pos @c_array_set(%Pos ${arr}, %Int ${index}, %Pos ${value})
|
|
96
|
+
ret %Pos %z
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Creates a copy of `arr`
|
|
101
|
+
*/
|
|
102
|
+
def copy[T](arr: Array[T]): Array[T] = {
|
|
103
|
+
with on[OutOfBounds].default { <> }; // should not happen
|
|
104
|
+
val len = arr.size;
|
|
105
|
+
val newArray = allocate[T](len);
|
|
106
|
+
copy[T](arr, 0, newArray, 0, len);
|
|
107
|
+
newArray
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Copies `length`-many elements from `from` to `to`
|
|
112
|
+
* starting at `start` (in `from`) and `offset` (in `to`)
|
|
113
|
+
*/
|
|
114
|
+
def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int): Unit / Exception[OutOfBounds] = {
|
|
115
|
+
val startValid = start >= 0 && start + length <= from.size
|
|
116
|
+
val offsetValid = offset >= 0 && offset + length <= to.size
|
|
117
|
+
|
|
118
|
+
def go(i: Int, j: Int, length: Int): Unit =
|
|
119
|
+
if (length > 0) {
|
|
120
|
+
to.unsafeSet(j, from.unsafeGet(i))
|
|
121
|
+
go(i + 1, j + 1, length - 1)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (startValid && offsetValid) go(start, offset, length)
|
|
125
|
+
else do raise(OutOfBounds(), "Array index out of bounds, when copying")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Derived operations:
|
|
129
|
+
|
|
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
|
+
*/
|
|
134
|
+
def get[T](arr: Array[T], index: Int): T / Exception[OutOfBounds] =
|
|
135
|
+
if (index >= 0 && index < arr.size) arr.unsafeGet(index)
|
|
136
|
+
else do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index))
|
|
137
|
+
|
|
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
|
+
*/
|
|
142
|
+
def set[T](arr: Array[T], index: Int, value: T): Unit / Exception[OutOfBounds] =
|
|
143
|
+
if (index >= 0 && index < arr.size) unsafeSet(arr, index, value)
|
|
144
|
+
else do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index))
|
|
145
|
+
|
|
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
|
+
*/
|
|
150
|
+
def build[T](size: Int) { index: Int => T }: Array[T] = {
|
|
151
|
+
val arr = allocate[T](size);
|
|
152
|
+
each(0, size) { i =>
|
|
153
|
+
unsafeSet(arr, i, index(i))
|
|
154
|
+
};
|
|
155
|
+
arr
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Utility functions:
|
|
159
|
+
|
|
160
|
+
def toList[T](arr: Array[T]): List[T] = {
|
|
161
|
+
var i = arr.size - 1;
|
|
162
|
+
var l = Nil[T]()
|
|
163
|
+
while (i >= 0) {
|
|
164
|
+
l = Cons(arr.unsafeGet(i), l)
|
|
165
|
+
i = i - 1
|
|
166
|
+
}
|
|
167
|
+
l
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
def foreach[T](arr: Array[T]){ action: T => Unit }: Unit =
|
|
171
|
+
each(0, arr.size) { i =>
|
|
172
|
+
val x: T = arr.unsafeGet(i)
|
|
173
|
+
action(x)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
def foreach[T](arr: Array[T]){ action: (T) {Control} => Unit }: Unit =
|
|
177
|
+
each(0, arr.size) { (i) {label} =>
|
|
178
|
+
val x: T = arr.unsafeGet(i)
|
|
179
|
+
action(x) {label}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
def foreachIndex[T](arr: Array[T]){ action: (Int, T) => Unit }: Unit =
|
|
183
|
+
each(0, arr.size) { i =>
|
|
184
|
+
val x: T = arr.unsafeGet(i)
|
|
185
|
+
action(i, x)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
def foreachIndex[T](arr: Array[T]){ action: (Int, T) {Control} => Unit }: Unit =
|
|
189
|
+
each(0, arr.size) { (i) {label} =>
|
|
190
|
+
val x: T = arr.unsafeGet(i)
|
|
191
|
+
action(i, x) {label}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
def sum(list: Array[Int]): Int = {
|
|
195
|
+
var acc = 0
|
|
196
|
+
list.foreach { x =>
|
|
197
|
+
acc = acc + x
|
|
198
|
+
}
|
|
199
|
+
acc
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Show Instances
|
|
203
|
+
// --------------
|
|
204
|
+
|
|
205
|
+
def show[A](arr: Array[A]) { showA: A => String }: String = {
|
|
206
|
+
var output = "Array("
|
|
207
|
+
val lastIndex = arr.size - 1
|
|
208
|
+
|
|
209
|
+
arr.foreachIndex { (index, a) =>
|
|
210
|
+
if (index == lastIndex) output = output ++ showA(a)
|
|
211
|
+
else output = output ++ showA(a) ++ ", "
|
|
212
|
+
}
|
|
213
|
+
output = output ++ ")"
|
|
214
|
+
|
|
215
|
+
output
|
|
216
|
+
}
|
|
217
|
+
def show(l: Array[Int]): String = show(l) { e => show(e) }
|
|
218
|
+
def show(l: Array[Double]): String = show(l) { e => show(e) }
|
|
219
|
+
def show(l: Array[Bool]): String = show(l) { e => show(e) }
|
|
220
|
+
def show(l: Array[String]): String = show(l) { e => e }
|
|
221
|
+
|
|
222
|
+
def println(l: Array[Int]): Unit = println(show(l))
|
|
223
|
+
def println(l: Array[Double]): Unit = println(show(l))
|
|
224
|
+
def println(l: Array[Bool]): Unit = println(show(l))
|
|
225
|
+
def println(l: Array[String]): Unit = println(show(l))
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module bench
|
|
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 =
|
|
12
|
+
js "Date.now() * 1000000"
|
|
13
|
+
chez "(timestamp)"
|
|
14
|
+
ml "IntInf.toInt (Time.toNanoseconds (Time.now ()))"
|
|
15
|
+
llvm """
|
|
16
|
+
%time_ptr = alloca { i64, i64 }
|
|
17
|
+
call i32 @clock_gettime(i32 0, ptr %time_ptr)
|
|
18
|
+
%time = load {i64, i64}, ptr %time_ptr
|
|
19
|
+
%time_seconds = extractvalue {i64, i64} %time, 0
|
|
20
|
+
%time_nanoseconds = extractvalue {i64, i64} %time, 1
|
|
21
|
+
%time_seconds_nanoseconds = mul nsw i64 %time_seconds, 1000000000
|
|
22
|
+
%result = add nsw i64 %time_seconds_nanoseconds, %time_nanoseconds
|
|
23
|
+
ret %Int %result
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
extern llvm """
|
|
27
|
+
declare i32 @clock_gettime(i32, ptr)
|
|
28
|
+
"""
|
|
29
|
+
|
|
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 =
|
|
37
|
+
js "Math.round(performance.now() * 1000000)"
|
|
38
|
+
default { timestamp() }
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Runs the block and returns the time in nanoseconds
|
|
42
|
+
*/
|
|
43
|
+
def timed { block: => Unit }: Int = {
|
|
44
|
+
val before = relativeTimestamp()
|
|
45
|
+
block()
|
|
46
|
+
val after = relativeTimestamp()
|
|
47
|
+
after - before
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit = {
|
|
51
|
+
def run(n: Int, report: Bool): Unit = {
|
|
52
|
+
if (n <= 0) { () } else {
|
|
53
|
+
val time = timed { block() };
|
|
54
|
+
if (report) { println(time) } else { () };
|
|
55
|
+
run(n - 1, report)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
run(warmup, false)
|
|
59
|
+
run(iterations, true)
|
|
60
|
+
}
|