#lang racket/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 scat-dwim scat-wrap-dynamic ) (require "../rpn.rkt" racket/match racket/stxparam (for-syntax "../ns-tx.rkt" racket/pretty racket/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 stx) (syntax-case stx () ((_ state-type (var ...) . expr) ;; (pretty-print (syntax->datum stx)) #`(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))) (else (error 'state-lambda "match failed for ~s, wanted type ~s" state 'state-type))))))) ;; 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)) ;; Dynamic scheme wrapping. This is used in the interactive Forth ;; console to provide "do-what-i-mean" behaviour. (define (scat-wrap-dynamic fn) (unless (procedure? fn) (error 'scat-wrap-dynamic "not a procedure: ~a\n" fn)) (state-lambda stack (stack) (update (apply (rpn-wrap-dynamic fn) stack)))) (define-syntax (scat-dwim stx) (syntax-case stx () ((_ id) (let ((pid (ns-prefixed #'(scat) #'id))) (if (identifier-binding pid) pid #'(scat-wrap-dynamic id))))))