[WIP] syntax-rules: rewrite syntax-rules.scm

[syntax-rules] bugfix

s/generate-representation/template-representation/g

[WIP] rewrite syntax-rules

[syntax-rules] bugfix

s/generate-representation/template-representation/g

[syntax-rules] bugfix
This commit is contained in:
Yuichi Nishiwaki 2015-06-13 15:49:57 +09:00
parent d741efe294
commit 43f1f6bb70
1 changed files with 162 additions and 316 deletions

View File

@ -1,348 +1,194 @@
(define-library (picrin syntax-rules) (define-library (picrin syntax-rules)
(import (picrin base) (import (picrin base)
(picrin control)
(picrin macro)) (picrin macro))
(define-syntax define-auxiliary-syntax (define-syntax (define-auxiliary-syntax var)
(er-macro-transformer #`(define-macro #,var
(lambda (expr r c) (lambda _
(list (r 'define-syntax) (cadr expr) (error "invalid use of auxiliary syntax" '#,var))))
(list (r 'lambda) '_
(list (r 'lambda) '_
(list (r 'error) (list (r 'string-append) "invalid use of auxiliary syntax: '" (symbol->string (cadr expr)) "'"))))))))
(define-auxiliary-syntax _) (define-auxiliary-syntax _)
(define-auxiliary-syntax ...) (define-auxiliary-syntax ...)
(define (walk proc expr) (define (succ n)
(cond (+ n 1))
((null? expr)
'())
((pair? expr)
(cons (walk proc (car expr))
(walk proc (cdr expr))))
((vector? expr)
(list->vector (map proc (vector->list expr))))
(else
(proc expr))))
(define (flatten expr) (define (pred n)
(let ((list '())) (if (= n 0)
(walk 0
(lambda (x) (- n 1)))
(set! list (cons x list)))
expr)
(reverse list)))
(define (reverse* l) (define (every? args)
;; (reverse* '(a b c d . e)) => (e d c b a) (if (null? args)
(let loop ((a '())
(d l))
(if (pair? d)
(loop (cons (car d) a) (cdr d))
(cons d a))))
(define (every? pred l)
(if (null? l)
#t #t
(and (pred (car l)) (every? pred (cdr l))))) (if (car args)
(every? (cdr args))
#f)))
(define-syntax syntax-rules (define (filter f list)
(er-macro-transformer (if (null? list)
(lambda (form r compare) '()
(define _define (r 'define)) (if (f (car list))
(define _let (r 'let)) (cons (car list)
(define _if (r 'if)) (filter f (cdr list)))
(define _begin (r 'begin)) (filter f (cdr list)))))
(define _lambda (r 'lambda))
(define _set! (r 'set!))
(define _not (r 'not))
(define _and (r 'and))
(define _car (r 'car))
(define _cdr (r 'cdr))
(define _cons (r 'cons))
(define _pair? (r 'pair?))
(define _null? (r 'null?))
(define _symbol? (r 'symbol?))
(define _vector? (r 'vector?))
(define _eqv? (r 'eqv?))
(define _string=? (r 'string=?))
(define _map (r 'map))
(define _vector->list (r 'vector->list))
(define _list->vector (r 'list->vector))
(define _quote (r 'quote))
(define _quasiquote (r 'quasiquote))
(define _unquote (r 'unquote))
(define _unquote-splicing (r 'unquote-splicing))
(define _syntax-error (r 'syntax-error))
(define _escape (r 'escape))
(define _er-macro-transformer (r 'er-macro-transformer))
(define (var->sym v) (define (map-keys f assoc)
(let loop ((cnt 0) (map (lambda (s) `(,(f (car s)) . ,(cdr s))) assoc))
(v v))
(if (symbol? v)
(string->symbol
(string-append (symbol->string v) "/" (number->string cnt)))
(loop (+ 1 cnt) (car v)))))
(define push-var list) (define (map-values f assoc)
(map (lambda (s) `(,(car s) . ,(f (cdr s)))) assoc))
(define (compile-match ellipsis literals pattern) ;; TODO
(letrec ((compile-match-base ;; - constants
(lambda (pattern) ;; - literals
(cond ((member pattern literals compare) ;; - custom ellipsis
(values ;; - splicing
`(,_if (,_and (,_symbol? expr) (cmp expr (rename ',pattern))) ;; - placeholder
#f ;; - vector
(exit #f))
'()))
((compare pattern (r '_)) (values #f '()))
((and ellipsis (compare pattern ellipsis))
(values `(,_syntax-error "invalid pattern") '()))
((symbol? pattern)
(values `(,_set! ,(var->sym pattern) expr) (list pattern)))
((pair? pattern)
(compile-match-list pattern))
((vector? pattern)
(compile-match-vector pattern))
((string? pattern)
(values
`(,_if (,_not (,_string=? ',pattern expr))
(exit #f))
'()))
(else
(values
`(,_if (,_not (,_eqv? ',pattern expr))
(exit #f))
'())))))
(compile-match-list ;; p ::= ()
(lambda (pattern) ;; | var
(let loop ((pattern pattern) ;; | (p . p)
(matches '()) ;; | (p ...)
(vars '())
(accessor 'expr))
(cond ;; (hoge)
((not (pair? (cdr pattern)))
(let*-values (((match1 vars1) (compile-match-base (car pattern)))
((match2 vars2) (compile-match-base (cdr pattern))))
(values
`(,_begin ,@(reverse matches)
(,_if (,_pair? ,accessor)
(,_begin
(,_let ((expr (,_car ,accessor)))
,match1)
(,_let ((expr (,_cdr ,accessor)))
,match2))
(exit #f)))
(append vars (append vars1 vars2)))))
;; (hoge ... rest args)
((and ellipsis (compare (cadr pattern) ellipsis))
(let-values (((match-r vars-r) (compile-match-list-reverse pattern)))
(values
`(,_begin ,@(reverse matches)
(,_let ((expr (,_let loop ((a ())
(d ,accessor))
(,_if (,_pair? d)
(loop (,_cons (,_car d) a) (,_cdr d))
(,_cons d a)))))
,match-r))
(append vars vars-r))))
(else
(let-values (((match1 vars1) (compile-match-base (car pattern))))
(loop (cdr pattern)
(cons `(,_if (,_pair? ,accessor)
(,_let ((expr (,_car ,accessor)))
,match1)
(exit #f))
matches)
(append vars vars1)
`(,_cdr ,accessor))))))))
(compile-match-list-reverse (define (compile ellipsis literals rules)
(lambda (pattern)
(let loop ((pattern (reverse* pattern))
(matches '())
(vars '())
(accessor 'expr))
(cond ((and ellipsis (compare (car pattern) ellipsis))
(let-values (((match1 vars1) (compile-match-ellipsis (cadr pattern))))
(values
`(,_begin ,@(reverse matches)
(,_let ((expr ,accessor))
,match1))
(append vars vars1))))
(else
(let-values (((match1 vars1) (compile-match-base (car pattern))))
(loop (cdr pattern)
(cons `(,_let ((expr (,_car ,accessor))) ,match1) matches)
(append vars vars1)
`(,_cdr ,accessor))))))))
(compile-match-ellipsis (define (many? pat)
(lambda (pattern) (and (pair? pat)
(let-values (((match vars) (compile-match-base pattern))) (pair? (cdr pat))
(values (variable? (cadr pat))
`(,_let loop ((expr expr)) (variable=? (cadr pat) ellipsis)
(,_if (,_not (,_null? expr)) (eq? (cddr pat) '())))
(,_let ,(map (lambda (var) `(,(var->sym var) '())) vars)
(,_let ((expr (,_car expr)))
,match)
,@(map
(lambda (var)
`(,_set! ,(var->sym (push-var var))
(,_cons ,(var->sym var) ,(var->sym (push-var var)))))
vars)
(loop (,_cdr expr)))))
(map push-var vars)))))
(compile-match-vector (define (pattern-validator pat) ; pattern -> validator
(lambda (pattern) (letrec
(let-values (((match vars) (compile-match-base (vector->list pattern)))) ((pattern-validator
(values (lambda (pat form)
`(,_if (,_vector? expr) (cond
(,_let ((expr (,_vector->list expr))) ((null? pat)
,match) #`(null? #,form))
(exit #f)) ((variable? pat)
vars))))) #t)
((many? pat)
(let ((validator (pattern-validator (car pat) 'it)))
#`(and (list? #,form)
(every? (map (lambda (#,'it) #,validator) #,form)))))
((pair? pat)
#`(and (pair? #,form)
#,(pattern-validator (car pat) #`(car #,form))
#,(pattern-validator (cdr pat) #`(cdr #,form))))
(else
#f)))))
(pattern-validator pat 'it)))
(let-values (((match vars) (compile-match-base (cdr pattern)))) (define (pattern-variables pat) ; pattern -> (freevar)
(values `(,_let ((expr (,_cdr expr))) (cond
,match ((null? pat)
#t) '())
vars)))) ((variable? pat)
`(,pat))
((many? pat)
(pattern-variables (car pat)))
((pair? pat)
(append (pattern-variables (car pat))
(pattern-variables (cdr pat))))))
;;; compile expand (define (pattern-levels pat) ; pattern -> ((var * int))
(define (compile-expand ellipsis reserved template) (cond
(letrec ((compile-expand-base ((null? pat)
(lambda (template ellipsis-valid) '())
(cond ((member template reserved eq?) ((variable? pat)
(values (var->sym template) (list template))) `((,pat . 0)))
((symbol? template) ((many? pat)
(values `(rename ',template) '())) (map-values succ (pattern-levels (car pat))))
((pair? template) ((pair? pat)
(compile-expand-list template ellipsis-valid)) (append (pattern-levels (car pat))
((vector? template) (pattern-levels (cdr pat))))))
(compile-expand-vector template ellipsis-valid))
(else
(values `',template '())))))
(compile-expand-list (define (pattern-selectors pat) ; pattern -> ((var * selector))
(lambda (template ellipsis-valid) (letrec
(let loop ((template template) ((pattern-selectors
(expands '()) (lambda (pat form)
(vars '())) (cond
(cond ;; (... hoge) ((null? pat)
((and ellipsis-valid '())
(pair? template) ((variable? pat)
(compare (car template) ellipsis)) `((,pat . ,form)))
(if (and (pair? (cdr template)) (null? (cddr template))) ((many? pat)
(compile-expand-base (cadr template) #f) (let ((envs (pattern-selectors (car pat) 'it)))
(values '(,_syntax-error "invalid template") '()))) (map-values (lambda (s) #`(map (lambda (#,'it) #,s) #,form)) envs)))
;; hoge ((pair? pat)
((not (pair? template)) (append (pattern-selectors (car pat) #`(car #,form))
(let-values (((expand1 vars1) (pattern-selectors (cdr pat) #`(cdr #,form))))))))
(compile-expand-base template ellipsis-valid))) (pattern-selectors pat 'it)))
(values
`(,_quasiquote (,@(reverse expands) . (,_unquote ,expand1)))
(append vars vars1))))
;; (a ... rest syms)
((and ellipsis-valid
(pair? (cdr template))
(compare (cadr template) ellipsis))
(let-values (((expand1 vars1)
(compile-expand-base (car template) ellipsis-valid)))
(loop (cddr template)
(cons
`(,_unquote-splicing
(,_map (,_lambda ,(map var->sym vars1) ,expand1)
,@(map (lambda (v) (var->sym (push-var v))) vars1)))
expands)
(append vars (map push-var vars1)))))
(else
(let-values (((expand1 vars1)
(compile-expand-base (car template) ellipsis-valid)))
(loop (cdr template)
(cons
`(,_unquote ,expand1)
expands)
(append vars vars1))))))))
(compile-expand-vector (define (template-representation pat levels selectors)
(lambda (template ellipsis-valid) (cond
(let-values (((expand1 vars1) ((null? pat)
(compile-expand-base (vector->list template) ellipsis-valid))) '())
(values ((variable? pat)
`(,_list->vector ,expand1) (let ((it (assq pat levels)))
vars1))))) (if it
(if (= 0 (cdr it))
(cdr (assq pat selectors))
(error "unmatched pattern variable level" pat))
#`'#,pat)))
((many? pat)
(letrec*
((inner-pat
(car pat))
(inner-vars
(filter (lambda (v) (assq v levels)) (pattern-variables inner-pat)))
(inner-tmps
(map (lambda (v) #'it) inner-vars))
(inner-levels
(map (lambda (s) `(,(car s) . ,(pred (cdr s)))) levels))
(inner-selectors
(map cons inner-vars inner-tmps))
(inner-rep
(template-representation inner-pat inner-levels inner-selectors))
(filtered-selectors
(map (lambda (v) (assq v selectors)) inner-vars))
;; ((a . (x1 x2)) (b . (y1 y2 y3)) (c . z1)) -> ((x1 x2) (y1 y2 y3) (z1))
(list-of-selectors
(map (lambda (x) (if (list? x) x (list x))) (map cdr filtered-selectors))))
#`(map (lambda #,inner-tmps #,inner-rep) #,@list-of-selectors)))
((pair? pat)
#`(cons #,(template-representation (car pat) levels selectors)
#,(template-representation (cdr pat) levels selectors)))))
(compile-expand-base template ellipsis))) (define (compile-rule pattern template)
(let ((levels
(pattern-levels pattern))
(selectors
(pattern-selectors pattern)))
(template-representation template levels selectors)))
(define (check-vars vars-pattern vars-template) (define (compile-rules rules)
;;fixme (if (null? rules)
#t) #`(error "unmatch")
(let ((pattern (car (car rules)))
(template (cadr (car rules))))
#`(if #,(pattern-validator pattern)
#,(compile-rule pattern template)
#,(compile-rules (cdr rules))))))
(define (compile-rule ellipsis literals rule) (define (compile rules)
(let ((pattern (car rule)) #`(lambda #,'it
(template (cadr rule))) #,(compile-rules rules)))
(let*-values (((match vars-match)
(compile-match ellipsis literals pattern))
((expand vars-expand)
(compile-expand ellipsis (flatten vars-match) template)))
(if (check-vars vars-match vars-expand)
(list vars-match match expand)
'mismatch))))
(define (expand-clauses clauses rename) (let ((rules (map-keys cdr rules))) ; TODO: check pattern head is a variable
(cond ((null? clauses) (compile rules)))
`(,_quote (syntax-error "no matching pattern")))
((compare (car clauses) 'mismatch)
`(,_syntax-error "invalid rule"))
(else
(let ((vars (list-ref (car clauses) 0))
(match (list-ref (car clauses) 1))
(expand (list-ref (car clauses) 2)))
`(,_let ,(map (lambda (v) (list (var->sym v) '())) vars)
(,_let ((result (,_escape (,_lambda (exit) ,match))))
(,_if result
,expand
,(expand-clauses (cdr clauses) rename))))))))
(define (normalize-form form) (define-syntax (syntax-rules . args)
(if (and (list? form) (>= (length form) 2)) (if (list? (car args))
(let ((ellipsis '...) #`(syntax-rules ... #,@args)
(literals (cadr form)) (let ((ellipsis (car args))
(rules (cddr form))) (literals (car (cdr args)))
(rules (cdr (cdr args))))
(compile ellipsis literals rules))))
(when (symbol? literals)
(set! ellipsis literals)
(set! literals (car rules))
(set! rules (cdr rules)))
(if (and (symbol? ellipsis)
(list? literals)
(every? symbol? literals)
(list? rules)
(every? (lambda (l) (and (list? l) (= (length l) 2))) rules))
(if (member ellipsis literals compare)
`(syntax-rules #f ,literals ,@rules)
`(syntax-rules ,ellipsis ,literals ,@rules))
#f))
#f))
(let ((form (normalize-form form)))
(if form
(let ((ellipsis (list-ref form 1))
(literals (list-ref form 2))
(rules (list-tail form 3)))
(let ((clauses (map (lambda (rule) (compile-rule ellipsis literals rule))
rules)))
`(,_er-macro-transformer
(,_lambda (expr rename cmp)
,(expand-clauses clauses r)))))
`(,_syntax-error "malformed syntax-rules"))))))
(export syntax-rules (export syntax-rules
_ _