#lang scheme/base
(require
"../scat-tx.ss"
"../tools-tx.ss"
(for-template
"../scat.ss"
"locals-runtime.ss"
scheme/base))
(provide locals-tx)
(define (stx-split stx sym)
(let next ((s stx) (l '()))
(if (stx-null? s)
(error 'stx-split-eof "looking for `~s' in: ~s"
sym (syntax->datum stx))
(let-values
(((head tail) (stx-uncons s)))
(if (eq? sym (syntax->datum head))
(values (reverse l) tail)
(next tail (cons head l)))))))
(define (rep-constant stx)
(rpn-compile #`(',#,stx)))
(define (locals-tx code exp)
(locals-generic rep-constant #'qw code exp))
(define (locals->wrapper local-rep tag locals-list before-expr)
(define closed-before
(rpn-close-expression before-expr))
(lambda (expr)
(syntax-case locals-list ()
((var ...)
#`(let ((state (#,closed-before #,(rpn-state))))
(let-values
(((state+ var ...)
(state-pop-unquote/locals
state
#,(length locals-list)
'#,tag)))
(let-ns
(macro)
#,(map
(lambda (v) #`(#,v #,(local-rep v)))
locals-list)
(let ((#,(rpn-state) state+))
#,expr))))))))
(define (locals-generic local-rep tag code expr)
(syntax-case code ()
((_ . locals/code+)
(let-values
(((locals code+)
(stx-split #'locals/code+ '\|)))
(rpn-current-close
(compose (rpn-current-close)
(locals->wrapper local-rep tag locals expr)))
((rpn-next) code+ (rpn-state))))))