Skip to content

Commit ba1a85f

Browse files
committed
Promises in user space
1 parent 8f3e00f commit ba1a85f

File tree

3 files changed

+116
-82
lines changed

3 files changed

+116
-82
lines changed

examples/stdlib/io/promise.effekt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import io
2+
import io/promise
23

34
def main() = {
45

libraries/common/io.effekt

Lines changed: 0 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
module io
22

33
import ref
4-
import queue
54

65
// Event Loop
76
// ----------
@@ -34,84 +33,3 @@ extern async def abort(): Nothing =
3433
call void @eraseStack(%Stack %stack)
3534
ret void
3635
"""
37-
38-
// Futures
39-
// -------
40-
41-
extern type Future[T]
42-
43-
extern global def allocate[T](): Future[T] =
44-
llvm """
45-
%future = call %Pos @c_future_make()
46-
ret %Pos %future
47-
"""
48-
49-
extern global def fill[T](future: Future[T], value: T): Unit =
50-
llvm """
51-
call void @c_future_fill(%Pos ${future}, %Pos ${value})
52-
ret %Pos zeroinitializer
53-
"""
54-
55-
extern async def wait[T](future: Future[T]): T =
56-
llvm """
57-
call void @c_future_wait(%Pos ${future}, %Stack %stack)
58-
ret void
59-
"""
60-
61-
extern llvm """
62-
declare %Pos @c_future_make()
63-
declare void @c_future_fill(%Pos, %Pos)
64-
declare void @c_future_wait(%Pos, %Stack)
65-
"""
66-
67-
// Promises
68-
// --------
69-
70-
extern type Promise[T]
71-
// = js "{resolve: ƒ, promise: Promise}"
72-
// = llvm "{tag: 0, obj: Promise*}"
73-
74-
def promise[T](task: Task[T]): Promise[T] = {
75-
val p = promise::make[T]();
76-
spawn(box { p.resolve(task()) });
77-
return p
78-
}
79-
80-
extern llvm """
81-
declare %Pos @c_promise_make()
82-
declare void @c_promise_resolve(%Pos, %Pos)
83-
declare void @c_promise_await(%Pos, %Neg)
84-
"""
85-
86-
extern async def await[T](promise: Promise[T]): T =
87-
js "$effekt.capture(k => ${promise}.promise.then(k))"
88-
llvm """
89-
call void @c_promise_await(%Pos ${promise}, %Stack %stack)
90-
ret void
91-
"""
92-
93-
extern async def resolve[T](promise: Promise[T], value: T): Unit =
94-
js "$effekt.capture(k => { ${promise}.resolve(${value}); return k($effekt.unit) })"
95-
llvm """
96-
call void @c_promise_resolve(%Pos ${promise}, %Pos ${value}, %Stack %stack)
97-
ret void
98-
"""
99-
100-
namespace promise {
101-
extern js """
102-
function promise$make() {
103-
let resolve;
104-
const promise = new Promise((res, rej) => {
105-
resolve = res;
106-
});
107-
return { resolve: resolve, promise: promise };
108-
}
109-
"""
110-
111-
extern io def make[T](): Promise[T] =
112-
js "promise$make()"
113-
llvm """
114-
%promise = call %Pos @c_promise_make()
115-
ret %Pos %promise
116-
"""
117-
}

libraries/common/io/promise.effekt

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
module io/promise
2+
3+
import io
4+
5+
// Futures
6+
// -------
7+
8+
extern type Future[T]
9+
10+
namespace future {
11+
extern global def allocate[T](): Future[T] =
12+
llvm """
13+
%future = call %Pos @c_future_make()
14+
ret %Pos %future
15+
"""
16+
}
17+
18+
extern global def fill[T](future: Future[T], value: T): Unit =
19+
llvm """
20+
call void @c_future_fill(%Pos ${future}, %Pos ${value})
21+
ret %Pos zeroinitializer
22+
"""
23+
24+
extern async def wait[T](future: Future[T]): T =
25+
llvm """
26+
call void @c_future_wait(%Pos ${future}, %Stack %stack)
27+
ret void
28+
"""
29+
30+
extern llvm """
31+
declare %Pos @c_future_make()
32+
declare void @c_future_fill(%Pos, %Pos)
33+
declare void @c_future_wait(%Pos, %Stack)
34+
"""
35+
36+
// Promises
37+
// --------
38+
39+
type State[T] {
40+
Resolved(value: T)
41+
Pending(futures: List[Future[T]])
42+
}
43+
44+
extern type Promise[T]
45+
// = js "{resolve: ƒ, promise: Promise}"
46+
// = llvm "Ref[State[T]]"
47+
48+
extern pure def toPromise[T](promise: Ref[State[T]]): Promise[T] =
49+
llvm """
50+
ret %Pos ${promise}
51+
"""
52+
53+
extern pure def toRefState[T](promise: Promise[T]): Ref[State[T]] =
54+
llvm """
55+
ret %Pos ${promise}
56+
"""
57+
58+
namespace promise {
59+
extern global def make[T](): Promise[T] =
60+
js "promise$make()"
61+
llvm { toPromise(ref(Pending(Nil()))) }
62+
}
63+
64+
def promise[T](task: Task[T]): Promise[T] = {
65+
val p = promise::make[T]();
66+
spawn(box { p.resolve(task()) });
67+
return p
68+
}
69+
70+
extern {async, global} def await[T](promise: Promise[T]): T =
71+
js "$effekt.capture(k => ${promise}.promise.then(k))"
72+
llvm {
73+
val reference = toRefState(promise)
74+
// TODO use reference.get
75+
get(reference) match {
76+
case Resolved(value) =>
77+
return value
78+
case Pending(futures) =>
79+
val future = future::allocate()
80+
// TODO user reference.set and future.wait
81+
set(reference, Pending(Cons(future, futures)))
82+
wait(future)
83+
}
84+
}
85+
86+
extern {io, global} def resolve[T](promise: Promise[T], value: T): Unit =
87+
js "promise$resolve(${promise}, ${value})"
88+
llvm {
89+
val reference = toRefState(promise)
90+
// TODO use reference.get
91+
get(reference) match {
92+
case Resolved(value) =>
93+
panic("ERROR: Promise already resolved")
94+
case Pending(futures) =>
95+
// TODO use reference.set
96+
set(reference, Resolved(value))
97+
futures.reverse.foreach { future => future.fill(value) }
98+
}
99+
}
100+
101+
102+
extern js """
103+
function promise$make() {
104+
let resolve;
105+
const promise = new Promise((res, rej) => {
106+
resolve = res;
107+
});
108+
return { resolve: resolve, promise: promise };
109+
}
110+
111+
function promise$resolve(promise, value) {
112+
promise.resolve(value);
113+
return $effekt.unit
114+
}
115+
"""

0 commit comments

Comments
 (0)