#lang scheme/base
(require
"../tools.ss"
"../tools-tx.ss"
"../scat-tx.ss"
scheme/pretty
(for-template
scheme/base
"../tools.ss"
"../scat.ss"
"pattern-runtime.ss"
scheme/match
))
(provide
asm-pattern-tx
asm-template-tx
asm-lambda-tx
asm-transforms-tx
with-asm-transforms-tx
check-opcodes-tx
)
(define (asm-pattern-tx stx)
(map
(lambda (ins)
(syntax-case ins (unquote)
(,instruction #'instruction)
((,tag arg ...) #`(list tag arg ...))
((,tag arg ... . args) #`(list-rest tag arg ... args))
((tag arg ...) (begin
(register-opcode ins)
#`(list 'tag arg ...)))))
(syntax->list stx)))
(define (asm-template-tx stx)
(syntax-case stx (macro:)
(((op arg ...) ...)
(begin
(for-each register-opcode (syntax->list stx))
#`(quasiquote ((op (unquote arg) ...) ...))))
(_ stx)))
(define (spec->name/match-clause stx)
(syntax-case stx ()
(((asm-pattern ... name) expr)
(values
(name->identifier #'name) (let ((pattern-lst
(reverse (asm-pattern-tx
#'(asm-pattern ...))))
(template
#`(macro/append-reverse #,(asm-template-tx #'expr)
rest)))
(if (null? pattern-lst)
#`(rest #,template)
#`((list-rest #,@pattern-lst rest) #,template)
))))))
(define (specs->clause-dict specs)
(map*
(lambda (name . orig/clause)
(list name
(map first orig/clause)
(map second orig/clause)))
(collect
free-identifier=?
(map
(lambda (orig)
(let-values
(((name clause)
(spec->name/match-clause orig)))
(cons name (list orig clause)))) (syntax->list specs)))))
(define (clauses->word name clauses)
#`(pattern-tx->macro
'#,name
#,(quasisyntax/loc
name
(match-lambda #,@clauses))))
(define (transform-bindings specs)
(map*
(lambda (name origs clauses)
#`(#,name
(make-word
#,(clauses->word name clauses)
'((pattern: . #,origs)))))
(specs->clause-dict specs)))
(define (asm-transforms-tx namespace specs)
(with-opcode-checks
(lambda ()
#`(redefinitions!-ns
#,namespace
#,@(transform-bindings specs)))))
(define (with-asm-transforms-tx namespace specs)
#`(lambda (thunk)
(parameterize-words-ns! #,namespace
#,(transform-bindings specs)
(thunk))))
(define (asm-lambda-tx specs)
(let* ((clause-dict
(specs->clause-dict specs)))
(apply
(lambda (origs clauses)
#`(make-word
#,(clauses->word #'<anonymous> clauses)
'((pattern . #,origs))))
(list
(apply append (map second clause-dict))
(apply append (map third clause-dict))))))
(define *opcodes* '())
(define (with-opcode-checks thunk)
(let ((out (thunk)))
out))
(define (register-opcode stx)
(syntax-case stx ()
((op . args)
(identifier? #'op)
(push! *opcodes*
(list #'op
(length (syntax->datum #'args)))))
(_ (void))))
(define (collect-opcodes)
(collect
equal?
(map*
(lambda (stx arity)
(list (syntax->datum stx)
arity
(syntax-source stx)
(syntax-line stx)
(syntax-column stx)
(syntax-position stx)
(syntax-span stx)))
*opcodes*)))
(define (report-opcodes)
(for-each*
(lambda (name . locs)
(printf "~a ~a\n" name (length locs)))
(collect-opcodes)))
(define (check-opcodes-tx stx)
(syntax-case stx ()
((_ asm-find)
#`(check-ops
asm-find
(quote #,(collect-opcodes))))))