;;; June 6, 1984
;;; This implementation of 3-lisp in 3-lisp is the one
;;; presented in the implementation paper [des Rivieres & Smith 84]
;;; This program does work, albeit slowly.  The examples which it 
;;; handled successfully were:
;;;
;;;     100
;;;     (+ 2 2)
;;;     (lambda simple [x] x)
;;;     ((lambda simple [x] x) 10)
;;;     (cond [$f 1] [(= 2 2) 4])
;;;     ((lambda reflect [a e c] (c '3)))
;;;     (set z 99)
;;; and (block 1 2)
;;;
;;; (and boy, was it slow!)

(define 3-LISP
  (lambda simple []
    (&&read-normalise-print (initial-tower 2) 1 global) ))
(define &&READ-NORMALISE-PRINT
  (lambda simple [state level env]
    (&&normalise state (:prompt&read level) env
      (make-reply-continuation level env) )))
(define &&REPLY-CONTINUATION
  (lambda simple [state result level env]
    (block 
      (:prompt&reply result level)
      (&&read-normalise-print state level env) )))
(define &&NORMALISE
  (lambda simple [state exp env cont]
    (block (print exp primary-stream) (newline primary-stream)
    (cond [(normal exp) (&&call state cont exp)]
          [(atom exp) (&&call state cont (binding exp env))]
          [(rail exp) (&&normalise-rail state exp env cont)]
          [(pair exp) (&&reduce state (car exp)
                         (cdr exp) env cont )]))) )
(define &&REDUCE
  (lambda simple [state proc args env cont]
    (&&normalise state proc env
      (make-proc-continuation proc args env cont) )))
(define &&PROC-CONTINUATION
  (lambda simple [state proc! proc args env cont]
    (if (reflective proc!)
        (&&call state \(de-reflect proc!) args env cont)
        (&&normalise state args env
          (make-args-continuation proc! proc args env cont) ))))
(define &&ARGS-CONTINUATION
  (lambda simple [state args! proc! proc args env cont]
    (if (or (primitive proc!) (kernel-utility proc!))
        (&&call state cont ↑(\proc! . \args!))
        (&&expand-closure state proc! args! cont) )))
(define &&EXPAND-CLOSURE
  (lambda simple [state proc! args! cont]
    (cond [(and (= (kernel-primary-type proc!) 'normalise)
                (plausible-arguments-to-normalise args!))
           (&&normalise (shift-down cont state) 
              \(1st args!) \(2nd args!) \(3rd args!))]
          [(and (kernel-continuation-closure proc!)
                (plausible-arguments-to-a-continuation args!))
           (&&call-continuation (shift-down cont state) 
              \proc! \(1st args!))]
          [$t (&&normalise state (body proc!)
                (bind (pattern proc!) args! (environment proc!))
                cont )]))) 
(define &&NORMALISE-RAIL
  (lambda simple [state rail env cont]
    (if (empty rail)
        (&&call state cont (rcons))
        (&&normalise state (1st rail) env
          (make-first-continuation rail env cont) ))))
(define &&FIRST-CONTINUATION
  (lambda simple [state first! rail env cont]
    (&&normalise-rail state (rest rail) env
      (make-rest-continuation first! rail env cont) )))
(define &&REST-CONTINUATION
  (lambda simple [state rest! first! rail env cont]
    (&&call state cont (prep first! rest!)) ))
(define &&LAMBDA
  (lambda simple [state [kind pattern body] env cont]
     (&&call state cont (ccons kind ↑env pattern body)) ))
(define &&IF
  (lambda simple [state [premise c1 c2] env cont]
    (&&normalise state premise env
      (make-if-continuation premise c1 c2 env cont) )))
(define &&IF-CONTINUATION
  (lambda simple [state premise! premise c1 c2 env cont]
     (&&normalise state (ef \premise! c1 c2) env cont) )) 
(define &&CALL
  (lambda simple x
    (let [[state (1st x)] [f (2nd x)] [a (rest (rest x))]]
      (cond [(kernel-primary-closure ↑f)
             (&&call-primary state f a)]
            [(and (kernel-continuation-closure ↑f)
                  (= (length a) 1))
             (&&call-continuation state f (1st a))]
            [(or (primitive ↑f) (kernel-utility ↑f))
             (&&call (shift-up state)
               (reify-continuation state) ↑(f . a))]
            [$t  
             (&&expand-closure (shift-up state)
               ↑f ↑a (reify-continuation state) )])))) 
(define &&CALL-PRIMARY
  (lambda simple [state f a]
    (select (kernel-primary-type ↑f)
      ['normalise
          (&&normalise state (1st a) (2nd a) (3rd a))]
      ['normalise-rail
          (&&normalise-rail state (1st a) (2nd a) (3rd a))]
      ['reduce
          (&&reduce state (1st a) (2nd a) (3rd a) (4th a))]
      ['read-normalise-print
          (&&read-normalise-print state (1st a) (2nd a))]
      ['if
          (&&if state (1st a) (2nd a) (3rd a))]
      ['lambda
          (&&lambda state (1st a) (2nd a) (3rd a)) ])))
(define &&CALL-CONTINUATION
  (lambda simple [state f arg]
    (select (kernel-continuation-type ↑f)
      ['proc  (&&proc-continuation state arg
                   (extract 'proc f) (extract 'args f)
                   (extract 'env f) (extract 'cont f))]
      ['args  (&&args-continuation state arg
                   (extract 'proc! f) (extract 'proc f)
                   (extract 'args f) (extract 'env f)
                   (extract 'cont f))]
      ['first (&&first-continuation state arg
                   (extract 'rail f) (extract 'env f)
                   (extract 'cont f))]
      ['rest  (&&rest-continuation state arg
                   (extract 'first! f) (extract 'rail f)
                   (extract 'env f) (extract 'cont f))]
      ['reply (&&reply-continuation state arg
                   (extract 'level f) (extract 'env f))]
      ['if    (&&if-continuation state arg
                   (extract 'premise f) (extract 'c1 f)
                   (extract 'c2 f) (extract 'env f)
                   (extract 'cont f) )])))
(define MAKE-PROC-CONTINUATION
  (lambda simple [proc args env cont]
    \(ccons 'simple ↑(bind '[proc args env cont reduce]
                          ↑[proc args env cont reduce] global)
        '[proc!]
        '(if (reflective proc!)
             (\(de-reflect proc!) args env cont)
             (normalise args env
                (lambda [args!]
                   (if (primitive proc!)
                       (cont ↑(\proc! . \args!))
                       (normalise (body proc!)
                                  (bind (pattern proc!) args!
                                        (environment proc!))
                                  cont ))))) )))
(define MAKE-ARGS-CONTINUATION
  (lambda simple [proc! proc args env cont]
    \(ccons 'simple ↑(bind '[proc! proc args env cont reduce]
                          ↑[proc! proc args env cont reduce] global)
        '[args!]
        '(if (primitive proc!)
             (cont ↑(\proc! . \args!))
             (normalise (body proc!)
                        (bind (pattern proc!) args!
                              (environment proc!))
                        cont )) )))
(define MAKE-FIRST-CONTINUATION
  (lambda simple [rail env cont]
    \(ccons 'simple ↑(bind '[rail env cont normalise-rail]
                          ↑[rail env cont normalise-rail] global)
        '[first!]
        '(normalise-rail (rest rail) env
            (lambda [rest!]
               (cont (prep first! rest!)) )) )))
(define MAKE-REST-CONTINUATION
  (lambda simple [first! rail env cont]
    \(ccons 'simple ↑(bind '[first! rail env cont normalise-rail]
                          ↑[first! rail env cont normalise-rail] global)
        '[rest!]
        '(cont (prep first! rest!)) )))
(define MAKE-REPLY-CONTINUATION
  (lambda simple [level env]
    \(ccons 'simple ↑(bind '[level env :read-normalise-print]
                    ↑[level env :read-normalise-print] global)
        '[result]
        '(block (:prompt&reply level result)
                (:read-normalise-print level env) ) )))
(define MAKE-IF-CONTINUATION
  (lambda simple [premise c1 c2 env cont]
    \(ccons 'simple ↑(bind '[premise c1 c2 env cont if]
                          ↑[premise c1 c2 env cont if] global)
        '[premise!]
        '(normalise (ef \premise! c1 c2) env cont) )))
(define INITIAL-TOWER 
  (lambda simple [level] (scons level)) )
(define SHIFT-DOWN 
  (lambda simple [continuation state]
    (block (print '<shifting-down> primary-stream) (newline primary-stream)
    (prep continuation state) )) )
(define REIFY-CONTINUATION 
  (lambda simple [state]
    (if (= (length state) 1)
        (make-reply-continuation (1st state) global)
        (1st state) )))
(define SHIFT-UP 
  (lambda simple [state]
    (block (print '<shifting-up> primary-stream) (newline primary-stream)
    (if (= (length state) 1)
        (scons (1+ (1st state)))
(define PLAUSIBLE-ARGUMENTS-TO-A-CONTINUATION
  (lambda simple [args!]
    (and (rail args!) (= (length args!) 1)
         (handle (1st args!)) )))
(define PLAUSIBLE-ARGUMENTS-TO-NORMALISE
  (lambda simple [args!]
    (block (print '<plausible> ps) (newline ps)
           (print args! ps) (newline ps)
    (and (rail args!) (= (length args!) 3)
         (handle (1st args!))
         (plausible-environment-designator (2nd args!))
         (plausible-continuation-designator (3rd args!)) ))) )
(define PLAUSIBLE-ENVIRONMENT-DESIGNATOR
  (lambda simple [env!]
     (and (rail env!)
          (or (= env! ↑global)
              (empty env!)
              (and (plausible-binding-designator (1st env!))
                   (plausible-environment-designator (rest env!)) )))))
(define PLAUSIBLE-BINDING-DESIGNATOR
  (lambda simple [b!]
    (and (rail b!) (= (length b!) 2)
         (handle (1st b!)) (atom \(1st b!))
         (handle (2nd b!)) )))
(define PLAUSIBLE-CONTINUATION-DESIGNATOR
  (lambda simple [c!]
    (and (closure c!) (not (reflective c!))
         (or (atom (pattern c!))
             (rail (pattern c!)) (= (length (pattern c!)) 1) ))))
(define EXTRACT 
  (lambda simple [variable function]
    \(binding variable (environment ↑function)) ))
(define KERNEL-PRIMARY-CLOSURE 
  (lambda simple [closure]
    (not (= 'unknown (kernel-primary-type closure))) ))
(define KERNEL-PRIMARY-TYPE
  (lambda simple [closure]
    (identify-closure closure *kernel-primary-table*) ))
(set *KERNEL-PRIMARY-TABLE*
   [['normalise ↑normalise]
    ['reduce ↑reduce]
    ['normalise-rail ↑normalise-rail]
    ['read-normalise-print ↑:read-normalise-print]
    ['lambda (de-reflect ↑lambda)]
    ['if (de-reflect ↑if)] ])
(define KERNEL-CONTINUATION-CLOSURE 
  (lambda simple [closure]
    (not (= 'unknown (kernel-continuation-type closure))) ))
(define KERNEL-CONTINUATION-TYPE
  (lambda simple [closure]
    (identify-closure closure *kernel-continuation-table*) ))
(set *KERNEL-CONTINUATION-TABLE*
   [['proc  ↑(make-proc-continuation  '? '? '? '?)]
    ['args  ↑(make-args-continuation  '? '? '? '? '?)]
    ['first ↑(make-first-continuation '? '? '?)]
    ['rest  ↑(make-rest-continuation  '? '? '? '?)]
    ['reply ↑(make-reply-continuation '? '?)]
    ['if    ↑(make-if-continuation    '? '? '? '? '?)] ])
(define KERNEL-UTILITY
  (lambda simple [closure]
    (member closure *kernel-utility-table*) ))
(set *KERNEL-UTILITY-TABLE*
  [↑binding ↑bind ↑rebind ↑de-reflect ↑primitive ↑reflective
   ↑normal  ↑length
   ↑append ↑append*
   ↑1st ↑2nd ↑3rd ↑4th ↑5th ↑6th ↑unit ↑double ↑member
   ↑:prompt&read ↑:prompt&reply ↑environment] )
(define IDENTIFY-CLOSURE
  (lambda simple [closure table]
    (cond [(empty table) 'unknown]
          [(similar-closure closure (2nd (1st table)))
           (1st (1st table))]
          [$T (identify-closure closure (rest table))] )))
(define SIMILAR-CLOSURE
  (lambda simple [closure template]
    (or (= closure template)
        (and (isomorphic (pattern closure) (pattern template))
             (isomorphic (body closure) (body template))
             (= (reflective closure) (reflective template))
             (similar-environment (environment closure)
                                  (environment template) ))))) 
(define SIMILAR-ENVIRONMENT
  (lambda simple [environment template]
    (or (= ↑environment ↑template)
        (and (empty environment) (empty template))
        (and (not (empty template))
             (not (empty environment))
             (= (1st (1st environment)) (1st (1st template)))
             (or (= ' '? (2nd (1st template)))
                 (= (2nd (1st environment)) (2nd (1st template))))
             (similar-environment (rest environment)
                                  (rest template) )))))





(define :read-normalise-print
   (lambda simple [level env]
      (normalise (:prompt&read level) env
         (lambda simple [result]
            (block (:prompt&reply result level)
                   (:read-normalise-print level env) ))))) 

(define :prompt&read
  (lambda simple [level]
    (prompt&read level primary-stream) ))
(define :prompt&reply
  (lambda simple [result level]
     (prompt&reply result level primary-stream) ))