#lang scheme/base

;; For the base SCAT language, the running state is a stack,
;; implemented as a list wrapped in a structure type.

(provide

 ;; base object
 state-lambda  update
 state-update      

 ;; stack
 stack
 stack-list
 stack-cons
 stack-uncons
 stack-top
 stack-lambda

 make-state:stack
 state:stack

 )

(require
 scheme/match
 scheme/stxparam
 (for-syntax
  scheme/base))

;; STATE Inheritance & functional update.

;; Read is handled by structure type inheritance. Write is implemented
;; through a factory method stored in the first 'update' field.

(define-struct state (update))  

(define-syntax-parameter update
  (lambda (stx)
    (raise-syntax-error #f "can only be used inside `state-lambda'" stx)))

;; Matcher for derived structures. Non-hygienically introduces 'update'.
;; FIXME: use syntax parameters (this guesses symbol context from state-type)
(define-syntax state-lambda
  (syntax-rules ()
    ((_ state-type (var ...) . expr)
     (lambda (state)
       (match state
              ((struct state-type (update-fn var ...))
               (let ((_update
                      (lambda args
                        (apply update-fn state args))))
                 (syntax-parameterize
                  ((update (make-rename-transformer #'_update)))
                  . expr))))))))


;; STACK object

;; Parameter stack = state object for the SCAT language. This is
;; extended with extra state for the MACRO language.

(define-struct (stack state) (list))  

(define (make-state:stack l)
  (let ((update ;; for object-name
         (lambda (state lst) (make-state:stack lst))))
    (make-stack update l)))

;; Type values are empty constructors.
(define (state:stack)
  (make-state:stack '()))
  

;; Stack update.
(define (stack-cons a s)
  ((state-lambda stack (l)
                 (update (cons a l)))
   s))
   
(define stack-uncons
  (state-lambda stack
                (stack)
                (unless (pair? stack)
                  (error 'stack-underflow))
                (values
                 (car stack)
                 (update (cdr stack)))))

;; Lift functions that operate on the scheme argument list to
;; functions operating on the stack struct.
(define-syntax stack-lambda
  (syntax-rules ()
    ((_ formals . body)
     (state-lambda stack
                   (stack)
                   (update
                    (apply (lambda formals . body) stack))))))

(define (stack-top s)
  (let-values
      (((top rest) (stack-uncons s)))
    top))




