#lang scheme/unit

;; Primitives for the control stack extension. This supports Forth's
;; control flow words, which are implemented in terms of jumps and
;; labels.

;; A practicaly Forth compiler implemented in will
;; replace the underlying jump/label mechanism with a more powerful
;; control flow analysis mechanism.


(import jump^ cjump^ stack^)
(export control^)

 ((m-swap)          (macro-prim: ctrl> ctrl> swap >ctrl >ctrl))
 ((m-dup)           (macro-prim: ctrl>       dup  >ctrl >ctrl))
 ((m>)              (macro-prim: ctrl> literal))
 (([qw a]  >m)      (macro-prim: ',a >ctrl))
 (([cw a]  word>m)  (macro-prim: ',a >ctrl))



 (macro) macro:

 ;; Mark basic block end. The label is not used, only the effect it
 ;; has: to split the basic block.

 ;; For control flow analysis we need to obtain the conditional branch
 ;; target so a basic block can have two exit paths. If each block has
 ;; only a single conditional exit, this is possible. (Maybe mark the
 ;; block as a branch block too?)
 (end:    sym label:)

 ;; 'if should be the ONLY macro calling the machine-specific 'jw/if
 ;; macro.
 (if      sym dup >m jw/false end:)
 (else    sym dup >m jw m-swap then)
 (then    m> label:) 

 (begin   sym dup >m label:)
 (again   m> jw)

 (do      begin)
 (while   if)
 (repeat  m-swap again then)
 (until   not while repeat)

 ;; Note: for .. next used to have an optimization wrapping the inner
 ;; loop in a dup .. drop construct. Given the current implementation,
 ;; this is not so straightforward to implement, so it's currently
 ;; disabled. The main problem being that the composition implementing
 ;; the loop body can't be recovered easily, and a more direct code
 ;; inspection mechanism is necessary.  However, using higher order
 ;; macros, this should be fairly trivial to do directly, so I'm not
 ;; bothering right now.
 ;; one with drop .. save wrapped around it. this generates better
 ;; code for loops that do 'read modify write'. platform specific
 ;; needs to define for0 ... next0
                                        ; (for1  dup for0 drop)
                                        ; (next1 save next0 drop)

 ;; amb-compile will non-deterministically compile (execute) one of
 ;; the two quoted macros. each macro quotes a macro implementing
 ;; its 'next' behavirour (next just executes macro from m>).
                                        ; (for   (for0 (constraint:label-nodup
                                        ;               next0) >m)
                                        ;        (for1 (next1) >m)
                                        ;        amb-compile)

                                        ; (amb-compile   swap >m >m m-amb-run/s)

                                        ; (next  m> compile)