@effekt-lang/effekt 0.52.0 → 0.54.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/cps/effekt.ss +169 -0
- package/libraries/common/buffer.effekt +2 -2
- package/libraries/common/effekt.effekt +1 -1
- package/libraries/common/io/channel.effekt +51 -0
- package/libraries/common/io/promise.effekt +53 -0
- package/libraries/common/io/signal.effekt +55 -0
- package/libraries/common/io/time.effekt +1 -1
- package/libraries/common/io.effekt +1 -57
- package/libraries/common/json.effekt +11 -8
- package/libraries/common/stream.effekt +1 -1
- package/libraries/js/mutable/map.effekt +2 -2
- package/libraries/llvm/io.c +38 -133
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +41 -66
- package/licenses/mit license - mit-license.html +27 -24
- package/licenses/the bsd license - bsd-license.html +26 -25
- package/licenses/the mit license - mit.html +27 -26
- package/package.json +1 -1
package/bin/effekt
CHANGED
|
Binary file
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
; Value = Any
|
|
2
|
+
; Generation = Int
|
|
3
|
+
|
|
4
|
+
; Ref = Store * Value * Generation
|
|
5
|
+
(define-record-type ref (fields store (mutable value) (mutable generation)))
|
|
6
|
+
|
|
7
|
+
; Node = box MEM | box Diff
|
|
8
|
+
|
|
9
|
+
; MEM
|
|
10
|
+
; Means the correct values are in MEMory
|
|
11
|
+
(define-record-type mem (fields))
|
|
12
|
+
|
|
13
|
+
; Diff = Ref * Value * Generation * Node
|
|
14
|
+
; Notes the DIFFerences between root and the current state in MEMory
|
|
15
|
+
(define-record-type diff (fields ref value generation root))
|
|
16
|
+
|
|
17
|
+
; Store = Node * Generation
|
|
18
|
+
(define-record-type store (fields (mutable root) (mutable generation)))
|
|
19
|
+
|
|
20
|
+
; Snapshot = Store * Node * Generation
|
|
21
|
+
(define-record-type snap (fields store root generation))
|
|
22
|
+
|
|
23
|
+
; -> Store
|
|
24
|
+
(define (create-store) (make-store (box (make-mem)) 0))
|
|
25
|
+
|
|
26
|
+
; Store -> Snapshot
|
|
27
|
+
(define (snapshot store)
|
|
28
|
+
(let* ([sGen (store-generation store)]
|
|
29
|
+
[snap (make-snap store (store-root store) sGen)])
|
|
30
|
+
(store-generation-set! store (+ sGen 1))
|
|
31
|
+
snap))
|
|
32
|
+
|
|
33
|
+
; Node, [box Diff] -> [box Diff]
|
|
34
|
+
(define (collectDiffs n acc)
|
|
35
|
+
(let ([unboxedN (unbox n)])
|
|
36
|
+
(cond
|
|
37
|
+
[(mem? unboxedN) acc]
|
|
38
|
+
[else (collectDiffs (diff-root unboxedN) (cons n acc))])))
|
|
39
|
+
|
|
40
|
+
; Node, [Diff] -> void
|
|
41
|
+
(define (applyDiffs n diffs)
|
|
42
|
+
(cond
|
|
43
|
+
[(null? diffs) (set-box! n (make-mem))]
|
|
44
|
+
[else
|
|
45
|
+
(let* ([currentDiff (car diffs)]
|
|
46
|
+
[realDiff (unbox currentDiff)]
|
|
47
|
+
[r (diff-ref realDiff)]
|
|
48
|
+
[oldValue (ref-value r)])
|
|
49
|
+
(ref-value-set! r (diff-value realDiff))
|
|
50
|
+
(set-box! n (make-diff r oldValue (ref-generation r) currentDiff))
|
|
51
|
+
(applyDiffs currentDiff (cdr diffs)))]))
|
|
52
|
+
|
|
53
|
+
; Node, Node -> void
|
|
54
|
+
(define (reroot newRoot oldRoot)
|
|
55
|
+
(applyDiffs oldRoot (collectDiffs newRoot '())))
|
|
56
|
+
|
|
57
|
+
; Store, Snapshot -> void
|
|
58
|
+
(define (restore snap)
|
|
59
|
+
(let* ([snapRoot (snap-root snap)]
|
|
60
|
+
[store (snap-store snap)]
|
|
61
|
+
[storeRoot (store-root store)])
|
|
62
|
+
(reroot snapRoot storeRoot)
|
|
63
|
+
(store-root-set! store snapRoot)))
|
|
64
|
+
|
|
65
|
+
; Cont a = a, MetaCont -> #
|
|
66
|
+
; Prompt = Int
|
|
67
|
+
|
|
68
|
+
; MetaCont = Cont * Prompt * Store | Snapshot * MetaCont?
|
|
69
|
+
; Holds a "copy" of k, as well as its prompt and store
|
|
70
|
+
(define-record-type meta-cont
|
|
71
|
+
(fields (mutable cont) prompt (mutable store) (mutable rest)))
|
|
72
|
+
|
|
73
|
+
; Value, MetaCont -> Ref
|
|
74
|
+
(define (var init ks)
|
|
75
|
+
(let ([store (meta-cont-store ks)])
|
|
76
|
+
(make-ref store init (store-generation store))))
|
|
77
|
+
|
|
78
|
+
; Ref -> Value
|
|
79
|
+
(define (get ref) (ref-value ref))
|
|
80
|
+
|
|
81
|
+
; Ref, Value -> void
|
|
82
|
+
(define (put ref value)
|
|
83
|
+
(let* ([rGen (ref-generation ref)]
|
|
84
|
+
[store (ref-store ref)]
|
|
85
|
+
[sGen (store-generation store)])
|
|
86
|
+
(if (= rGen sGen)
|
|
87
|
+
(ref-value-set! ref value)
|
|
88
|
+
(let ([oldVal (ref-value ref)]
|
|
89
|
+
[newRoot (box (make-mem))]
|
|
90
|
+
[oldRoot (store-root store)])
|
|
91
|
+
(ref-value-set! ref value)
|
|
92
|
+
(ref-generation-set! ref sGen)
|
|
93
|
+
(set-box! oldRoot (make-diff ref oldVal rGen newRoot))
|
|
94
|
+
(store-root-set! store newRoot)))))
|
|
95
|
+
|
|
96
|
+
; MetaCont -> MetaCont
|
|
97
|
+
(define (create-region ks) ks)
|
|
98
|
+
|
|
99
|
+
; Value, MetaCont -> Ref
|
|
100
|
+
(define allocate var)
|
|
101
|
+
|
|
102
|
+
; Ref | MetaCont -> void
|
|
103
|
+
(define (deallocate _) (void))
|
|
104
|
+
|
|
105
|
+
(define _prompt 1)
|
|
106
|
+
(define (new-prompt)
|
|
107
|
+
(let ([prompt _prompt])
|
|
108
|
+
(set! _prompt (+ prompt 1))
|
|
109
|
+
prompt))
|
|
110
|
+
|
|
111
|
+
(define (top-level-k x _) x)
|
|
112
|
+
(define top-level-ks (make-meta-cont top-level-k 0 (create-store) '()))
|
|
113
|
+
|
|
114
|
+
; a, MetaCont -> #
|
|
115
|
+
(define (return x ks)
|
|
116
|
+
(let* ([new-ks (meta-cont-rest ks)]
|
|
117
|
+
[k (meta-cont-cont new-ks)])
|
|
118
|
+
(k x new-ks)))
|
|
119
|
+
|
|
120
|
+
; Program a b = a, Cont b, MetaCont -> #
|
|
121
|
+
|
|
122
|
+
; Program Prompt b, MetaCont, Cont b -> #
|
|
123
|
+
(define (reset prog ks k)
|
|
124
|
+
(let ([prompt (new-prompt)])
|
|
125
|
+
(meta-cont-cont-set! ks k)
|
|
126
|
+
(prog prompt (make-meta-cont return prompt (create-store) ks) return)))
|
|
127
|
+
|
|
128
|
+
; MetaCont, Prompt -> MetaCont * MetaCont
|
|
129
|
+
(define (split-stack ks p)
|
|
130
|
+
(define (worker above below)
|
|
131
|
+
(let ([new-below (meta-cont-rest below)]
|
|
132
|
+
[snap (snapshot (meta-cont-store below))])
|
|
133
|
+
(meta-cont-store-set! below snap)
|
|
134
|
+
(meta-cont-rest-set! below above)
|
|
135
|
+
(if (= (meta-cont-prompt below) p)
|
|
136
|
+
(values below new-below)
|
|
137
|
+
(worker below new-below))))
|
|
138
|
+
(worker '() ks))
|
|
139
|
+
|
|
140
|
+
; Prompt, Program MetaCont b, MetaCont, Cont b -> #
|
|
141
|
+
(define (shift p prog ks k)
|
|
142
|
+
(meta-cont-cont-set! ks k)
|
|
143
|
+
(let-values ([(c underC) (split-stack ks p)])
|
|
144
|
+
(prog c underC (meta-cont-cont underC))))
|
|
145
|
+
|
|
146
|
+
; MetaCont, MetaCont -> MetaCont
|
|
147
|
+
(define (rewind cont ks)
|
|
148
|
+
(if (null? cont)
|
|
149
|
+
ks
|
|
150
|
+
(let* ([snap (meta-cont-store cont)]
|
|
151
|
+
[next (meta-cont-rest cont)]
|
|
152
|
+
[newKs (make-meta-cont (meta-cont-cont cont)
|
|
153
|
+
(meta-cont-prompt cont)
|
|
154
|
+
(snap-store snap)
|
|
155
|
+
ks)])
|
|
156
|
+
(restore snap)
|
|
157
|
+
(rewind next newKs))))
|
|
158
|
+
|
|
159
|
+
; Block b = Cont b, MetaCont -> #
|
|
160
|
+
|
|
161
|
+
; MetaCont, Block, MetaCont, Cont -> #
|
|
162
|
+
(define (resume cont block ks k)
|
|
163
|
+
(meta-cont-cont-set! ks k)
|
|
164
|
+
(let ([rewinded (rewind cont ks)])
|
|
165
|
+
(block rewinded (meta-cont-cont rewinded))))
|
|
166
|
+
|
|
167
|
+
; Block b -> b
|
|
168
|
+
(define (run-top-level p)
|
|
169
|
+
(p top-level-ks top-level-k))
|
|
@@ -48,7 +48,7 @@ def arrayBuffer[T](initialCapacity: Int): Buffer[T] at global = {
|
|
|
48
48
|
def full?() = capacity() <= 0
|
|
49
49
|
def empty?() = size() <= 0
|
|
50
50
|
def read() = {
|
|
51
|
-
if (
|
|
51
|
+
if (size() <= 0) None()
|
|
52
52
|
else {
|
|
53
53
|
val result: T = contents.unsafeGet(head.get)
|
|
54
54
|
head.set(mod(head.get + 1, initialCapacity))
|
|
@@ -56,7 +56,7 @@ def arrayBuffer[T](initialCapacity: Int): Buffer[T] at global = {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
def write(el: T) = {
|
|
59
|
-
if (
|
|
59
|
+
if (capacity() <= 0) <> // raise(BufferOverflow())
|
|
60
60
|
|
|
61
61
|
contents.unsafeSet(tail.get, el)
|
|
62
62
|
tail.set(mod(tail.get + 1, initialCapacity))
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module io/channel
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import io/signal
|
|
5
|
+
|
|
6
|
+
record Node[A, B](this: Signal[A, B], rest: Ref[Option[Node[A, B]]])
|
|
7
|
+
|
|
8
|
+
type Sender[A, B] = Ref[Node[A, B]]
|
|
9
|
+
type Receiver[A, B] = Ref[Node[A, B]]
|
|
10
|
+
|
|
11
|
+
/// Creates a new rendezvous channel and returns the receiving and the sending end.
|
|
12
|
+
/// Every send must be matched by exactly one receive upon which two values are exchanged.
|
|
13
|
+
def channel[A, B](): (Sender[A, B], Receiver[A, B]) = {
|
|
14
|
+
val node = Node(signal(), ref(None()))
|
|
15
|
+
(ref(node), ref(node))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// Sends a value to a channel and blocks until a receiver arrives.
|
|
19
|
+
def send[A, B](sender: Sender[A, B], value: A): B = {
|
|
20
|
+
val Node(this, rest) = sender.get()
|
|
21
|
+
rest.get() match {
|
|
22
|
+
case None() =>
|
|
23
|
+
val node = Node(signal(), ref(None()))
|
|
24
|
+
rest.set(Some(node))
|
|
25
|
+
sender.set(node)
|
|
26
|
+
case Some(node) =>
|
|
27
|
+
sender.set(node)
|
|
28
|
+
}
|
|
29
|
+
// TODO avoid yield
|
|
30
|
+
yield()
|
|
31
|
+
this.unsafeFire(value)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// Receives a value from a channel and blocks until a sender arrives.
|
|
35
|
+
def receive[A, B](receiver: Receiver[A, B], value: B): A = {
|
|
36
|
+
val Node(this, rest) = receiver.get()
|
|
37
|
+
rest.get() match {
|
|
38
|
+
case None() =>
|
|
39
|
+
val node = Node(signal(), ref(None()))
|
|
40
|
+
rest.set(Some(node))
|
|
41
|
+
receiver.set(node)
|
|
42
|
+
case Some(node) =>
|
|
43
|
+
receiver.set(node)
|
|
44
|
+
}
|
|
45
|
+
// TODO avoid yield
|
|
46
|
+
yield()
|
|
47
|
+
this.unsafeWait(value)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// TODO streaming
|
|
51
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module io/promise
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import io/signal
|
|
5
|
+
|
|
6
|
+
// Promises
|
|
7
|
+
// --------
|
|
8
|
+
|
|
9
|
+
type State[T] {
|
|
10
|
+
Pending(signals: List[Signal[T, Unit]])
|
|
11
|
+
Resolved(value: T)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type Promise[T] = Ref[State[T]]
|
|
15
|
+
|
|
16
|
+
namespace promise {
|
|
17
|
+
/// Creates a pending promise that must be resolved exactly once
|
|
18
|
+
/// and can be awaited multiple times.
|
|
19
|
+
def make[T](): Promise[T] =
|
|
20
|
+
ref(Pending(Nil()))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Spawns a task and immediately returns a promise that upon completion
|
|
24
|
+
/// of the task will resolve to its result.
|
|
25
|
+
def promise[T](task: () => T at {io, async, global}): Promise[T] = {
|
|
26
|
+
val p = promise::make[T]();
|
|
27
|
+
spawn(box { p.resolve(task()) });
|
|
28
|
+
return p
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Awaits and blocks until the given promise is resolved.
|
|
32
|
+
def await[T](promise: Promise[T]): T =
|
|
33
|
+
promise.get match {
|
|
34
|
+
case Resolved(value) =>
|
|
35
|
+
return value
|
|
36
|
+
case Pending(signals) =>
|
|
37
|
+
val signal = signal()
|
|
38
|
+
promise.set(Pending(Cons(signal, signals)))
|
|
39
|
+
// TODO perhaps yield to avoid stack overflow
|
|
40
|
+
signal.unsafeWait(())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Resolves the given promise, unblocking all awaiting tasks.
|
|
44
|
+
def resolve[T](promise: Promise[T], value: T): Unit =
|
|
45
|
+
promise.get match {
|
|
46
|
+
case Resolved(value) =>
|
|
47
|
+
panic("ERROR: Promise already resolved")
|
|
48
|
+
case Pending(signals) =>
|
|
49
|
+
promise.set(Resolved(value))
|
|
50
|
+
// TODO perhaps yield to avoid stack overflow
|
|
51
|
+
signals.reverse.foreach { signal => unsafeFire(signal, value) }
|
|
52
|
+
}
|
|
53
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module io/signal
|
|
2
|
+
|
|
3
|
+
// Signals
|
|
4
|
+
// -------
|
|
5
|
+
|
|
6
|
+
/// Must be fired exactly once with an A receiving a B,
|
|
7
|
+
/// and must be waited for exactly once with a B receiving an A.
|
|
8
|
+
extern type Signal[A, B]
|
|
9
|
+
|
|
10
|
+
extern def signal[A, B]() at global: Signal[A, B] =
|
|
11
|
+
js "signal$make()"
|
|
12
|
+
llvm """
|
|
13
|
+
%signal = call %Pos @c_signal_make()
|
|
14
|
+
ret %Pos %signal
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
extern def unsafeFire[A, B](signal: Signal[A, B], value: A) at async: B =
|
|
18
|
+
js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
|
|
19
|
+
llvm """
|
|
20
|
+
call void @c_signal_notify(%Pos ${signal}, %Pos ${value}, %Stack %stack)
|
|
21
|
+
ret void
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
extern def unsafeWait[A, B](signal: Signal[A, B], value: B) at async: A =
|
|
25
|
+
js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
|
|
26
|
+
llvm """
|
|
27
|
+
call void @c_signal_notify(%Pos ${signal}, %Pos ${value}, %Stack %stack)
|
|
28
|
+
ret void
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
extern llvm """
|
|
32
|
+
declare %Pos @c_signal_make()
|
|
33
|
+
declare void @c_signal_notify(%Pos, %Pos, %Stack)
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
extern js """
|
|
37
|
+
function signal$make() {
|
|
38
|
+
return { state: 0, value: null, stack: null };
|
|
39
|
+
}
|
|
40
|
+
function signal$notify(signal, value, stack) {
|
|
41
|
+
if (signal.state === 0) {
|
|
42
|
+
signal.state = 1;
|
|
43
|
+
signal.value = value;
|
|
44
|
+
signal.stack = stack;
|
|
45
|
+
} else {
|
|
46
|
+
const otherValue = signal.value;
|
|
47
|
+
const otherStack = signal.stack;
|
|
48
|
+
signal.value = null;
|
|
49
|
+
signal.stack = null;
|
|
50
|
+
|
|
51
|
+
otherStack(value);
|
|
52
|
+
stack(otherValue);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
"""
|
|
@@ -4,7 +4,7 @@ extern llvm """
|
|
|
4
4
|
declare void @c_timer_start(%Int, %Stack)
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
extern def
|
|
7
|
+
extern def sleep(millis: Int) at async: Unit =
|
|
8
8
|
js "$effekt.capture(k => setTimeout(() => k($effekt.unit), ${millis}))"
|
|
9
9
|
llvm """
|
|
10
10
|
call void @c_timer_start(%Int ${millis}, %Stack %stack)
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
module io
|
|
2
2
|
|
|
3
|
-
import ref
|
|
4
|
-
import queue
|
|
5
3
|
|
|
6
4
|
// Event Loop
|
|
7
5
|
// ----------
|
|
8
6
|
|
|
9
|
-
type Task[T] = () => T at {io, async, global}
|
|
10
|
-
|
|
11
7
|
extern llvm """
|
|
12
8
|
declare void @c_yield(%Stack)
|
|
13
9
|
"""
|
|
14
10
|
|
|
15
|
-
extern def spawn(task:
|
|
11
|
+
extern def spawn[T](task: () => T at {io, async, global}) at async: Unit =
|
|
16
12
|
js "$effekt.capture(k => { setTimeout(() => k($effekt.unit), 0); return $effekt.run(${task}) })"
|
|
17
13
|
llvm """
|
|
18
14
|
call void @c_yield(%Stack %stack)
|
|
@@ -34,55 +30,3 @@ extern def abort() at async: Nothing =
|
|
|
34
30
|
ret void
|
|
35
31
|
"""
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
// Promises
|
|
39
|
-
// --------
|
|
40
|
-
|
|
41
|
-
extern type Promise[T]
|
|
42
|
-
// = js "{resolve: ƒ, promise: Promise}"
|
|
43
|
-
// = llvm "{tag: 0, obj: Promise*}"
|
|
44
|
-
|
|
45
|
-
def promise[T](task: Task[T]): Promise[T] = {
|
|
46
|
-
val p = promise::make[T]();
|
|
47
|
-
spawn(box { p.resolve(task()) });
|
|
48
|
-
return p
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
extern llvm """
|
|
52
|
-
declare %Pos @c_promise_make()
|
|
53
|
-
declare void @c_promise_resolve(%Pos, %Pos)
|
|
54
|
-
declare void @c_promise_await(%Pos, %Neg)
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
extern def await[T](promise: Promise[T]) at async: T =
|
|
58
|
-
js "$effekt.capture(k => ${promise}.promise.then(k))"
|
|
59
|
-
llvm """
|
|
60
|
-
call void @c_promise_await(%Pos ${promise}, %Stack %stack)
|
|
61
|
-
ret void
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
extern def resolve[T](promise: Promise[T], value: T) at async: Unit =
|
|
65
|
-
js "$effekt.capture(k => { ${promise}.resolve(${value}); return k($effekt.unit) })"
|
|
66
|
-
llvm """
|
|
67
|
-
call void @c_promise_resolve(%Pos ${promise}, %Pos ${value}, %Stack %stack)
|
|
68
|
-
ret void
|
|
69
|
-
"""
|
|
70
|
-
|
|
71
|
-
namespace promise {
|
|
72
|
-
extern js """
|
|
73
|
-
function promise$make() {
|
|
74
|
-
let resolve;
|
|
75
|
-
const promise = new Promise((res, rej) => {
|
|
76
|
-
resolve = res;
|
|
77
|
-
});
|
|
78
|
-
return { resolve: resolve, promise: promise };
|
|
79
|
-
}
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
extern def make[T]() at io: Promise[T] =
|
|
83
|
-
js "promise$make()"
|
|
84
|
-
llvm """
|
|
85
|
-
%promise = call %Pos @c_promise_make()
|
|
86
|
-
ret %Pos %promise
|
|
87
|
-
"""
|
|
88
|
-
}
|
|
@@ -327,15 +327,18 @@ namespace test {
|
|
|
327
327
|
def k = new JsonObjectBuilder {
|
|
328
328
|
def field(k){v} = { println(k); ignore{v} }
|
|
329
329
|
}
|
|
330
|
-
def
|
|
331
|
-
def
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
330
|
+
def jsonBuilder[R] {e: => R / JsonBuilder}: R = {
|
|
331
|
+
def d = new JsonBuilder {
|
|
332
|
+
def number(n) = println(n)
|
|
333
|
+
def bool(b) = ()
|
|
334
|
+
def null() = println("NULL")
|
|
335
|
+
def string(s) = ()
|
|
336
|
+
def list(){e} = jsonBuilder{e}
|
|
337
|
+
def dict(){e} = handleJsonObjectBuilder{k}{e}
|
|
338
|
+
}
|
|
339
|
+
handleJsonBuilder{d}{e}
|
|
337
340
|
}
|
|
338
|
-
|
|
341
|
+
jsonBuilder { decodeJson() }
|
|
339
342
|
}
|
|
340
343
|
|
|
341
344
|
println("")
|
|
@@ -5,7 +5,7 @@ import array
|
|
|
5
5
|
// A mutable map, backed by a JavaScript Map.
|
|
6
6
|
extern type Map[K, V]
|
|
7
7
|
|
|
8
|
-
extern def emptyMap[K, V]() at
|
|
8
|
+
extern def emptyMap[K, V]() at io: Map[K, V] =
|
|
9
9
|
js "new Map()"
|
|
10
10
|
|
|
11
11
|
def get[K, V](m: Map[K, V], key: K): Option[V] =
|
|
@@ -28,4 +28,4 @@ extern def values[K, V](map: Map[K, V]) at {}: Array[V] =
|
|
|
28
28
|
js "Array.from(${map}.values())"
|
|
29
29
|
|
|
30
30
|
extern def keys[K, V](map: Map[K, V]) at {}: Array[K] =
|
|
31
|
-
js "Array.from(${map}.keys())"
|
|
31
|
+
js "Array.from(${map}.keys())"
|
package/libraries/llvm/io.c
CHANGED
|
@@ -572,154 +572,59 @@ void c_yield(Stack stack) {
|
|
|
572
572
|
c_timer_start(0, stack);
|
|
573
573
|
}
|
|
574
574
|
|
|
575
|
-
|
|
576
|
-
// Promises
|
|
575
|
+
// Signals
|
|
577
576
|
// --------
|
|
578
577
|
|
|
579
|
-
typedef enum {
|
|
580
|
-
|
|
581
|
-
typedef struct Listeners {
|
|
582
|
-
Stack head;
|
|
583
|
-
struct Listeners* tail;
|
|
584
|
-
} Listeners;
|
|
578
|
+
typedef enum { INITIAL, NOTIFIED } signal_state_t;
|
|
585
579
|
|
|
586
580
|
typedef struct {
|
|
587
581
|
uint64_t rc;
|
|
588
582
|
void* eraser;
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
// }
|
|
594
|
-
union {
|
|
595
|
-
struct Pos value;
|
|
596
|
-
Listeners listeners;
|
|
597
|
-
} payload;
|
|
598
|
-
} Promise;
|
|
599
|
-
|
|
600
|
-
void c_promise_erase_listeners(void *envPtr) {
|
|
601
|
-
// envPtr points to a Promise _after_ the eraser, so let's adjust it to point to the promise.
|
|
602
|
-
Promise *promise = (Promise*) (envPtr - offsetof(Promise, state));
|
|
603
|
-
promise_state_t state = promise->state;
|
|
604
|
-
|
|
605
|
-
Stack head;
|
|
606
|
-
Listeners* tail;
|
|
607
|
-
Listeners* current;
|
|
608
|
-
|
|
609
|
-
switch (state) {
|
|
610
|
-
case UNRESOLVED:
|
|
611
|
-
head = promise->payload.listeners.head;
|
|
612
|
-
tail = promise->payload.listeners.tail;
|
|
613
|
-
if (head != NULL) {
|
|
614
|
-
// Erase head
|
|
615
|
-
eraseStack(head);
|
|
616
|
-
// Erase tail
|
|
617
|
-
current = tail;
|
|
618
|
-
while (current != NULL) {
|
|
619
|
-
head = current->head;
|
|
620
|
-
tail = current->tail;
|
|
621
|
-
free(current);
|
|
622
|
-
eraseStack(head);
|
|
623
|
-
current = tail;
|
|
624
|
-
};
|
|
625
|
-
};
|
|
626
|
-
break;
|
|
627
|
-
case RESOLVED:
|
|
628
|
-
erasePositive(promise->payload.value);
|
|
629
|
-
break;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
583
|
+
signal_state_t state;
|
|
584
|
+
struct Pos value;
|
|
585
|
+
Stack stack;
|
|
586
|
+
} Signal;
|
|
632
587
|
|
|
633
|
-
void
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
c_promise_resume_listeners(tail, value);
|
|
639
|
-
sharePositive(value);
|
|
640
|
-
resume_Pos(head, value);
|
|
641
|
-
}
|
|
588
|
+
void c_signal_erase(void *envPtr) {
|
|
589
|
+
// envPtr points to a Signal _after_ the eraser, so let's adjust it to point to the beginning.
|
|
590
|
+
Signal *signal = (Signal*) (envPtr - offsetof(Signal, state));
|
|
591
|
+
erasePositive(signal->value);
|
|
592
|
+
if (signal->stack != NULL) { eraseStack(signal->stack); }
|
|
642
593
|
}
|
|
643
594
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
Stack head;
|
|
648
|
-
Listeners* tail;
|
|
595
|
+
struct Pos c_signal_make() {
|
|
596
|
+
Signal* f = (Signal*)malloc(sizeof(Signal));
|
|
649
597
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
598
|
+
f->rc = 0;
|
|
599
|
+
f->eraser = c_signal_erase;
|
|
600
|
+
f->state = INITIAL;
|
|
601
|
+
f->value = (struct Pos) { .tag = 0, .obj = NULL, };
|
|
602
|
+
f->stack = NULL;
|
|
654
603
|
|
|
655
|
-
|
|
656
|
-
p->payload.value = value;
|
|
657
|
-
resume_Pos(stack, Unit);
|
|
658
|
-
|
|
659
|
-
if (head != NULL) {
|
|
660
|
-
// Execute tail
|
|
661
|
-
c_promise_resume_listeners(tail, value);
|
|
662
|
-
// Execute head
|
|
663
|
-
sharePositive(value);
|
|
664
|
-
resume_Pos(head, value);
|
|
665
|
-
};
|
|
666
|
-
break;
|
|
667
|
-
case RESOLVED:
|
|
668
|
-
erasePositive(promise);
|
|
669
|
-
erasePositive(value);
|
|
670
|
-
eraseStack(stack);
|
|
671
|
-
fprintf(stderr, "ERROR: Promise already resolved\n");
|
|
672
|
-
exit(1);
|
|
673
|
-
break;
|
|
674
|
-
}
|
|
675
|
-
// TODO stack overflow?
|
|
676
|
-
// We need to erase the promise now, since we consume it.
|
|
677
|
-
erasePositive(promise);
|
|
604
|
+
return (struct Pos) { .tag = 0, .obj = f, };
|
|
678
605
|
}
|
|
679
606
|
|
|
680
|
-
void
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
switch (p->state) {
|
|
689
|
-
case UNRESOLVED:
|
|
690
|
-
head = p->payload.listeners.head;
|
|
691
|
-
tail = p->payload.listeners.tail;
|
|
692
|
-
if (head != NULL) {
|
|
693
|
-
node = (Listeners*)malloc(sizeof(Listeners));
|
|
694
|
-
node->head = head;
|
|
695
|
-
node->tail = tail;
|
|
696
|
-
p->payload.listeners.head = stack;
|
|
697
|
-
p->payload.listeners.tail = node;
|
|
698
|
-
} else {
|
|
699
|
-
p->payload.listeners.head = stack;
|
|
700
|
-
};
|
|
607
|
+
void c_signal_notify(struct Pos signal, struct Pos value, Stack stack) {
|
|
608
|
+
Signal* f = (Signal*)signal.obj;
|
|
609
|
+
switch (f->state) {
|
|
610
|
+
case INITIAL: {
|
|
611
|
+
f->state = NOTIFIED;
|
|
612
|
+
f->value = value;
|
|
613
|
+
f->stack = stack;
|
|
614
|
+
erasePositive(signal);
|
|
701
615
|
break;
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
616
|
+
}
|
|
617
|
+
case NOTIFIED: {
|
|
618
|
+
struct Pos other_value = f->value;
|
|
619
|
+
f->value = (struct Pos) { .tag = 0, .obj = NULL, };
|
|
620
|
+
Stack other_stack = f->stack;
|
|
621
|
+
f->stack = NULL;
|
|
622
|
+
erasePositive(signal);
|
|
623
|
+
resume_Pos(other_stack, value);
|
|
624
|
+
resume_Pos(stack, other_value);
|
|
706
625
|
break;
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
erasePositive(promise);
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
struct Pos c_promise_make() {
|
|
713
|
-
Promise* promise = (Promise*)malloc(sizeof(Promise));
|
|
714
|
-
|
|
715
|
-
promise->rc = 0;
|
|
716
|
-
promise->eraser = c_promise_erase_listeners;
|
|
717
|
-
promise->state = UNRESOLVED;
|
|
718
|
-
promise->payload.listeners.head = NULL;
|
|
719
|
-
promise->payload.listeners.tail = NULL;
|
|
720
|
-
|
|
721
|
-
return (struct Pos) { .tag = 0, .obj = promise, };
|
|
626
|
+
}
|
|
627
|
+
}
|
|
722
628
|
}
|
|
723
629
|
|
|
724
|
-
|
|
725
630
|
#endif
|