@effekt-lang/effekt 0.53.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 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))
@@ -22,7 +22,7 @@ namespace chez {
22
22
 
23
23
  // CPS implementation
24
24
  // ------------------
25
- extern include chezLift "../chez/lift/effekt.ss"
25
+ extern include chezCPS "../chez/cps/effekt.ss"
26
26
 
27
27
  // Monadic implementation
28
28
  // ----------------------
@@ -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 wait(millis: Int) at async: Unit =
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: Task[Unit]) at async: Unit =
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
- }
@@ -44,7 +44,7 @@ def fix[T] { one: T => Unit / emit[T] } { stream: => Unit / emit[T] }: Unit =
44
44
  try {
45
45
  stream()
46
46
  } with emit[T] { value =>
47
- fix[T] {one} { one(value) }
47
+ fix {one} { one(value) }
48
48
  resume(())
49
49
  }
50
50
 
@@ -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 {}: Map[K, V] =
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())"
@@ -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 { UNRESOLVED, RESOLVED } promise_state_t;
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
- promise_state_t state;
590
- // state of {
591
- // case UNRESOLVED => Possibly empty (head is NULL) list of listeners
592
- // case RESOLVED => Pos (the result)
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 c_promise_resume_listeners(Listeners* listeners, struct Pos value) {
634
- if (listeners != NULL) {
635
- Stack head = listeners->head;
636
- Listeners* tail = listeners->tail;
637
- free(listeners);
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
- void c_promise_resolve(struct Pos promise, struct Pos value, Stack stack) {
645
- Promise* p = (Promise*)promise.obj;
646
-
647
- Stack head;
648
- Listeners* tail;
595
+ struct Pos c_signal_make() {
596
+ Signal* f = (Signal*)malloc(sizeof(Signal));
649
597
 
650
- switch (p->state) {
651
- case UNRESOLVED:
652
- head = p->payload.listeners.head;
653
- tail = p->payload.listeners.tail;
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
- p->state = RESOLVED;
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 c_promise_await(struct Pos promise, Stack stack) {
681
- Promise* p = (Promise*)promise.obj;
682
-
683
- Stack head;
684
- Listeners* tail;
685
- Listeners* node;
686
- struct Pos value;
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
- case RESOLVED:
703
- value = p->payload.value;
704
- sharePositive(value);
705
- resume_Pos(stack, value);
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
- // TODO hmm, stack overflow?
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