aboutsummaryrefslogtreecommitdiffstats
path: root/macros.scm
blob: 169602878c6c32ca30506b4907be1f1c2cb007cb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
(define inline-dup
  ;; [x] -> [x x]
  '(1 (#f jump) #f 1 call/cc))

(define inline-drop
  ;; [x] -> []
  '(0 (#f jump) #f 2 call/cc))

(define inline-dropn
  ;; [x1 ... xn xn+1 ...] -> [x1 ... xn+1 ...]
  (lambda (n)
    `(,n
      (#f                              ; [K n x1 ... xn xn+1 ...]
       jump)
      #f ,(+ n 2) call/cc)))

(define inline-pick
  ;; [x1 ... xn] -> [xn x1 ... xn]
  (lambda (n)
    `(1                                ; [1 x1 ... xn]
      (#f 2                            ; [2 K 1 x1 ... xn]
          (#f jump)                    ; [K' 2 K 1 x1 ... xn]
          #f ,(+ 3 n) call/cc          ; [K 1 xn ...]
          jump)
      #f 1 call/cc)))

(define inline-roll
  (lambda (n)
    `(,@(inline-pick n) ,@(inline-dropn (+ n 1)))))

(define stack-closure
  ;; Push a procedure to the stack that, when executed, will have the
  ;; current stack (plus whatever is pushed to it).
  ;; 
  ;; The arguments to the stack closure are [N returnK self values ...],
  ;; where `N` is the total number of values to pass to the procedure
  ;; (`returnK` and `self` excluded).
  (lambda (procedure n m)
    `((#f                              ; [next v ...]
       (#f                             ; [K next v ...]
        #f 3 ,@(inline-pick 2)         ; [K 3 #f K next v ...]
        jump)
       ,m ,(+ n 1) call/cc
       ;; This is the entry-point into the continuation.
       ;; 
       ;; [regular? K arg1 values ...]
       ;; When `regular?` is false, then `K` is the captured continuation,
       ;; and `arg1` is the continuation of this macro.
       ;; When `regular?` is true, then `K` is the return continuation, and
       ;; `arg1` is the number of arguments to the procedure body.
       #t eqv?
       (#f                             ; false: [K next]
        ;; The following is the returned procedure.
        (#f                            ; [returnK N self values ...]
         ,@(inline-pick 2) 0 ref       ; [K-here returnK N self values ...]
         #t ,@(inline-pick 3) 4 +      ; [(+ N 4) #t K-here returnK N self values ...]
         ,@(inline-roll 2)             ; [K-here (+ N 4) #t returnK N self values ...]
         jump)                         ; [proc K next]
        ,@inline-dup                   ; [proc proc K next]
        ,@(inline-roll 2)              ; [K proc proc next]
        0 set!                         ; [proc next]
        1 ,@(inline-roll 2)            ; [next 1 proc]
        jump)
       ,procedure if)
      #f 0 call/cc)))