#lang scheme/base
(require
scheme/match
scheme/control
scheme/struct-info
(for-template scheme/base
scheme/match)
(for-syntax scheme/base))
(provide (all-defined-out))
(define (form->clauses form)
(define hash (make-hash))
(for-each
(lambda (clause)
(match (syntax->list clause)
((list-rest name expr)
(let ((key (syntax->datum name)))
(when (hash-ref hash key (lambda () #f))
(raise-syntax-error 'duplicate-name
"Form contains duplicate name"
clause name))
(hash-set! hash key clause)))))
(syntax->list form))
hash)
(define (clauses-ref/mark-defined! clauses r)
(define (default) (list (datum->syntax #f r)))
(let ((clause (hash-ref clauses r default)))
(hash-set! clauses r #f)
clause))
(define (clauses-check-undefined dict)
(hash-map dict
(lambda (key notused)
(when notused
(raise-syntax-error 'undefined-register
"Undefined register"
notused
(datum->syntax notused key)
)))))
(define (machine-nf registers stx)
(let* ((dict (form->clauses stx))
(nf (datum->syntax
stx
(for/list ((r registers))
(syntax-case (clauses-ref/mark-defined! dict r) ()
((reg -> expr) #`(reg reg expr))
((reg : pat -> expr) #`(reg pat expr))
((reg) #`(reg reg reg))
((reg pat) #`(reg pat reg))
((reg pat expr) #`(reg pat expr))
)))))
(clauses-check-undefined dict)
nf))
(define (simple-pattern nf)
(syntax-case nf ()
(((reg pat expr) ...)
(for ((_p (syntax->list #'(pat ...))))
(let ((p (syntax-e _p)))
(unless (and (symbol? p))
(raise-syntax-error 'compound-pattern
"Machine expression contains pattern instead of identifier"
nf _p))))))
nf)
(define (machine-update-struct-tx i struct-id registers-stx stx)
(let* ((info (extract-struct-info (syntax-local-value struct-id)))
(make-struct-id (cadr info))
(size (length (cadddr info)))
(registers (syntax->datum registers-stx)))
(when (< size (length registers))
(raise-syntax-error #f "Too many fields" registers-stx))
(let ((registers
(append registers
(for/list ((n (in-range (- size (length registers)))))
(string->uninterned-symbol (format "R~s" n))))))
(syntax-case (machine-nf registers stx) ()
(((reg pat expr) ...)
#`(match #,i
((struct #,struct-id (pat ...))
(#,make-struct-id expr ...))))))))