clean up code

This commit is contained in:
Yuito Murase 2014-04-03 15:30:42 +09:00
parent 85db821ad2
commit 7af2f1e11d
1 changed files with 294 additions and 308 deletions

View File

@ -1,335 +1,321 @@
(import (scheme base) (define-library (picrin syntax-rules)
(scheme cxr) (import (scheme base)
(picrin macro) (scheme cxr)
(scheme write)) (picrin macro))
;;; utility functions ;;; utility functions
(define (reverse* l) (define (reverse* l)
;; (reverse* '(a b c d . e)) => (e d c b a) ;; (reverse* '(a b c d . e)) => (e d c b a)
(let loop ((a '()) (let loop ((a '())
(d l)) (d l))
(if (pair? d) (if (pair? d)
(loop (cons (car d) a) (cdr d)) (loop (cons (car d) a) (cdr d))
(cons d a)))) (cons d a))))
(define (var->sym v) (define (var->sym v)
(let loop ((cnt 0) (let loop ((cnt 0)
(v v)) (v v))
(if (symbol? v) (if (symbol? v)
(string->symbol (string-append (symbol->string v) "/" (number->string cnt))) (string->symbol (string-append (symbol->string v) "/" (number->string cnt)))
(loop (+ 1 cnt) (car v))))) (loop (+ 1 cnt) (car v)))))
(define push-var list) (define push-var list)
(define (every? pred l) (define (every? pred l)
(if (null? l) (if (null? l)
#t #t
(and (pred (car l)) (every? pred (cdr l))))) (and (pred (car l)) (every? pred (cdr l)))))
(define (flatten l) (define (flatten l)
(cond (cond
((null? l) '()) ((null? l) '())
((pair? (car l)) ((pair? (car l))
(append (flatten (car l)) (flatten (cdr l)))) (append (flatten (car l)) (flatten (cdr l))))
(else (else
(cons (car l) (flatten (cdr l)))))) (cons (car l) (flatten (cdr l))))))
;;; main function ;;; main function
(define-syntax syntax-rules (define-syntax syntax-rules
(er-macro-transformer (er-macro-transformer
(lambda (form r compare) (lambda (form r compare)
(define _define (r 'define)) (define _define (r 'define))
(define _let (r 'let)) (define _let (r 'let))
(define _if (r 'if)) (define _if (r 'if))
(define _begin (r 'begin)) (define _begin (r 'begin))
(define _lambda (r 'lambda)) (define _lambda (r 'lambda))
(define _set! (r 'set!)) (define _set! (r 'set!))
(define _not (r 'not)) (define _not (r 'not))
(define _and (r 'and)) (define _and (r 'and))
(define _car (r 'car)) (define _car (r 'car))
(define _cdr (r 'cdr)) (define _cdr (r 'cdr))
(define _cons (r 'cons)) (define _cons (r 'cons))
(define _pair? (r 'pair?)) (define _pair? (r 'pair?))
(define _null? (r 'null?)) (define _null? (r 'null?))
(define _symbol? (r 'symbol?)) (define _symbol? (r 'symbol?))
(define _eqv? (r 'eqv?)) (define _eqv? (r 'eqv?))
(define _string=? (r 'string=?)) (define _string=? (r 'string=?))
(define _map (r 'map)) (define _map (r 'map))
(define _vector->list (r 'vector->list)) (define _vector->list (r 'vector->list))
(define _list->vector (r 'list->vector)) (define _list->vector (r 'list->vector))
(define _quote (r 'quote)) (define _quote (r 'quote))
(define _quasiquote (r 'quasiquote)) (define _quasiquote (r 'quasiquote))
(define _unquote (r 'unquote)) (define _unquote (r 'unquote))
(define _unquote-splicing (r 'unquote-splicing)) (define _unquote-splicing (r 'unquote-splicing))
(define _syntax-error (r 'syntax-error)) (define _syntax-error (r 'syntax-error))
(define _call/cc (r 'call/cc)) (define _call/cc (r 'call/cc))
(define _er-macro-transformer (r 'er-macro-transformer)) (define _er-macro-transformer (r 'er-macro-transformer))
(define (compile-match ellipsis literals pattern) (define (compile-match ellipsis literals pattern)
(letrec ((compile-match-base (letrec ((compile-match-base
(lambda (pattern) (lambda (pattern)
(cond ((compare pattern (r '_)) (values #f '())) (cond ((compare pattern (r '_)) (values #f '()))
((member pattern literals compare) ((member pattern literals compare)
(values (values
`(,_if (,_and (,_symbol? expr) (cmp expr (rename ',pattern))) `(,_if (,_and (,_symbol? expr) (cmp expr (rename ',pattern)))
#f #f
(exit #f)) (exit #f))
'())) '()))
((and ellipsis (compare pattern ellipsis)) ((and ellipsis (compare pattern ellipsis))
(values `(,_syntax-error "invalid pattern") '())) (values `(,_syntax-error "invalid pattern") '()))
((symbol? pattern) ((symbol? pattern)
(values `(,_set! ,(var->sym pattern) expr) (list pattern))) (values `(,_set! ,(var->sym pattern) expr) (list pattern)))
((pair? pattern) ((pair? pattern)
(compile-match-list pattern)) (compile-match-list pattern))
((vector? pattern) ((vector? pattern)
(compile-match-vector pattern)) (compile-match-vector pattern))
((string? pattern) ((string? pattern)
(values (values
`(,_if (,_not (,_string=? ',pattern expr)) `(,_if (,_not (,_string=? ',pattern expr))
(exit #f)) (exit #f))
'())) '()))
(else
(values
`(,_if (,_not (,_eqv? ',pattern expr))
(exit #f))
'())))))
(compile-match-list
(lambda (pattern)
(let loop ((pattern pattern)
(matches '())
(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
(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 (else
(let-values (((match1 vars1) (compile-match-base (car pattern)))) (values
(loop (cdr pattern) `(,_if (,_not (,_eqv? ',pattern expr))
(cons `(,_let ((expr (,_car ,accessor))) ,match1) matches) (exit #f))
(append vars vars1) '())))))
`(,_cdr ,accessor))))))))
(compile-match-ellipsis (compile-match-list
(lambda (pattern) (lambda (pattern)
(let-values (((match vars) (compile-match-base pattern))) (let loop ((pattern pattern)
(values (matches '())
`(,_let loop ((expr expr)) (vars '())
(,_if (,_not (,_null? expr)) (accessor 'expr))
(,_let ,(map (lambda (var) `(,(var->sym var) '())) vars) (cond ;; (hoge)
(,_let ((expr (,_car expr))) ((not (pair? (cdr pattern)))
,match) (let*-values (((match1 vars1) (compile-match-base (car pattern)))
,@(map ((match2 vars2) (compile-match-base (cdr pattern))))
(lambda (var) (values
`(,_set! ,(var->sym (push-var var)) `(,_begin ,@(reverse matches)
(,_cons ,(var->sym var) ,(var->sym (push-var var))))) (,_if (,_pair? ,accessor)
vars) (,_begin
(loop (,_cdr expr))))) (,_let ((expr (,_car ,accessor)))
(map push-var vars))))) ,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-vector (compile-match-list-reverse
(lambda (pattern) (lambda (pattern)
(let-values (((match vars) (compile-match-list (vector->list pattern)))) (let loop ((pattern (reverse* pattern))
(values (matches '())
`(,_let ((expr (,_vector->list expr))) (vars '())
,match) (accessor 'expr))
vars))))) (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))))))))
(let-values (((match vars) (compile-match-base (cdr pattern)))) (compile-match-ellipsis
(values `(,_let ((expr (,_cdr expr))) (lambda (pattern)
,match (let-values (((match vars) (compile-match-base pattern)))
#t) (values
vars)))) `(,_let loop ((expr expr))
(,_if (,_not (,_null? expr))
(,_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 expand (compile-match-vector
(define (compile-expand ellipsis reserved template) (lambda (pattern)
(letrec ((compile-expand-base (let-values (((match vars) (compile-match-list (vector->list pattern))))
(lambda (template ellipsis-valid) (values
(cond ((member template reserved compare) `(,_let ((expr (,_vector->list expr)))
(values (var->sym template) (list template))) ,match)
((symbol? template) vars)))))
(values `(rename ',template) '()))
((pair? template)
(compile-expand-list template ellipsis-valid))
((vector? template)
(compile-expand-vector template ellipsis-valid))
(else
(values `',template '())))))
(compile-expand-list (let-values (((match vars) (compile-match-base (cdr pattern))))
(lambda (template ellipsis-valid) (values `(,_let ((expr (,_cdr expr)))
(let loop ((template template) ,match
(expands '()) #t)
(vars '())) vars))))
(cond ;; (... hoge)
((and ellipsis-valid
(pair? template)
(compare (car template) ellipsis))
(if (and (pair? (cdr template)) (null? (cddr template)))
(compile-expand-base (cadr template) #f)
(values '(,_syntax-error "invalid template") '())))
;; hoge
((not (pair? template))
(let-values (((expand1 vars1)
(compile-expand-base template ellipsis-valid)))
(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 ;;; compile expand
(lambda (template ellipsis-valid) (define (compile-expand ellipsis reserved template)
(let-values (((expand1 vars1) (letrec ((compile-expand-base
(compile-expand-list (vector->list template) ellipsis-valid))) (lambda (template ellipsis-valid)
`(,_list->vector ,expand1) (cond ((member template reserved compare)
vars1)))) (values (var->sym template) (list template)))
((symbol? template)
(values `(rename ',template) '()))
((pair? template)
(compile-expand-list template ellipsis-valid))
((vector? template)
(compile-expand-vector template ellipsis-valid))
(else
(values `',template '())))))
(compile-expand-base template ellipsis))) (compile-expand-list
(lambda (template ellipsis-valid)
(let loop ((template template)
(expands '())
(vars '()))
(cond ;; (... hoge)
((and ellipsis-valid
(pair? template)
(compare (car template) ellipsis))
(if (and (pair? (cdr template)) (null? (cddr template)))
(compile-expand-base (cadr template) #f)
(values '(,_syntax-error "invalid template") '())))
;; hoge
((not (pair? template))
(let-values (((expand1 vars1)
(compile-expand-base template ellipsis-valid)))
(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))))))))
(define (check-vars vars-pattern vars-template) (compile-expand-vector
;;fixme (lambda (template ellipsis-valid)
#t) (let-values (((expand1 vars1)
(compile-expand-list (vector->list template) ellipsis-valid)))
`(,_list->vector ,expand1)
vars1))))
(define (compile-rule ellipsis literals rule) (compile-expand-base template ellipsis)))
(let ((pattern (car rule))
(template (cadr rule)))
(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) (define (check-vars vars-pattern vars-template)
(cond ((null? clauses) ;;fixme
`(,_quote (syntax-error "no matching pattern"))) #t)
((compare (car clauses) 'mismatch)
`(,_syntax-error "invalid rule"))
(else
(let ((vars (car (car clauses)))
(match (cadr (car clauses)))
(expand (caddr (car clauses))))
`(,_let ,(map (lambda (v) (list (var->sym v) '())) vars)
(,_let ((result (,_call/cc (,_lambda (exit) ,match))))
(,_if result
,expand
,(expand-clauses (cdr clauses) rename))))))))
(define (normalize-form form) (define (compile-rule ellipsis literals rule)
(if (and (list? form) (>= (length form) 2)) (let ((pattern (car rule))
(let ((ellipsis '...) (template (cadr rule)))
(literals (cadr form)) (let*-values (((match vars-match)
(rules (cddr form))) (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))))
(when (symbol? literals) (define (expand-clauses clauses rename)
(set! ellipsis literals) (cond ((null? clauses)
(set! literals (car rules)) `(,_quote (syntax-error "no matching pattern")))
(set! rules (cdr rules))) ((compare (car clauses) 'mismatch)
`(,_syntax-error "invalid rule"))
(else
(let ((vars (car (car clauses)))
(match (cadr (car clauses)))
(expand (caddr (car clauses))))
`(,_let ,(map (lambda (v) (list (var->sym v) '())) vars)
(,_let ((result (,_call/cc (,_lambda (exit) ,match))))
(,_if result
,expand
,(expand-clauses (cdr clauses) rename))))))))
(if (and (symbol? ellipsis) (define (normalize-form form)
(list? literals) (if (and (list? form) (>= (length form) 2))
(every? symbol? literals) (let ((ellipsis '...)
(list? rules) (literals (cadr form))
(every? (lambda (l) (and (list? l) (= (length l) 2))) rules)) (rules (cddr form)))
(if (member ellipsis literals compare)
`(syntax-rules #f ,literals ,@rules)
`(syntax-rules ,ellipsis ,literals ,@rules))
#f))
#f))
(let ((form (normalize-form form))) (when (symbol? literals)
(if form (set! ellipsis literals)
(let ((ellipsis (cadr form)) (set! literals (car rules))
(literals (caddr form)) (set! rules (cdr rules)))
(rules (cdddr form)))
(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")))))) (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))
;;; test code (let ((form (normalize-form form)))
(import (scheme write)) (if form
(let ((ellipsis (cadr form))
(literals (caddr form))
(rules (cdddr form)))
(let ((clauses (map (lambda (rule) (compile-rule ellipsis literals rule))
rules)))
`(,_er-macro-transformer
(,_lambda (expr rename cmp)
,(expand-clauses clauses r)))))
(define-syntax hoge `(,_syntax-error "malformed syntax-rules"))))))
(syntax-rules ()
((hoge (a ...) ...) '((a ...) ...))
((hoge (a b) ...) '(a ...))
((hoge a b ... c . d) 'c)))
(display (hoge (1 2 3) (3 4 5) (5 6 7))) (export syntax-rules))
(newline)
(display (hoge (a b) (c d) (e f)))
(newline)
(display (hoge a b c))
(newline)