;*---------------------------------------------------------------------*/ ;* Copyright (c) 1997 by Manuel Serrano. All rights reserved. */ ;* */ ;* ,--^, */ ;* _ ___/ /|/ */ ;* ,;'( )__, ) ' */ ;* ;; // L__. */ ;* ' \ / ' */ ;* ^ ^ */ ;* */ ;* */ ;* This program is distributed in the hope that it will be useful. */ ;* Use and copying of this software and preparation of derivative */ ;* works based upon this software are permitted, so long as the */ ;* following conditions are met: */ ;* o credit to the authors is acknowledged following */ ;* current academic behaviour */ ;* o no fees or compensation are charged for use, copies, */ ;* or access to this software */ ;* o this copyright notice is included intact. */ ;* This software is made available AS IS, and no warranty is made */ ;* about the software or its performance. */ ;* */ ;* Bug descriptions, use reports, comments or suggestions are */ ;* welcome Send them to */ ;* Manuel Serrano -- Manuel.Serrano@cui.unige.ch */ ;*---------------------------------------------------------------------*/ (module __match_normalize (import (__error "Llib/error.scm") (__match_s2cfun "Match/s2cfun.scm")) (use (__type "Llib/type.scm") (__bigloo "Llib/bigloo.scm") (__tvector "Llib/tvector.scm") (__structure "Llib/struct.scm") (__tvector "Llib/tvector.scm") (__rgc "Rgc/runtime.scm") (__r4_numbers_6_5 "Ieee/number.scm") (__r4_numbers_6_5_fixnum "Ieee/fixnum.scm") (__r4_numbers_6_5_flonum "Ieee/flonum.scm") (__r4_characters_6_6 "Ieee/char.scm") (__r4_equivalence_6_2 "Ieee/equiv.scm") (__r4_booleans_6_1 "Ieee/boolean.scm") (__r4_symbols_6_4 "Ieee/symbol.scm") (__r4_strings_6_7 "Ieee/string.scm") (__r4_pairs_and_lists_6_3 "Ieee/pair-list.scm") (__r4_input_6_10_2 "Ieee/input.scm") (__r4_control_features_6_9 "Ieee/control.scm") (__r4_vectors_6_8 "Ieee/vector.scm") (__r4_ports_6_10_1 "Ieee/port.scm") (__r4_output_6_10_3 "Ieee/output.scm") (__evenv "Eval/evenv.scm")) (export (normalize-pattern pat) ;STk (match-define-structure! exp) (extend.r.macro-env name fun))) ;;;===========================================================4 ;;; The standardizer converts patterns with an ;;; extended syntax into pattern within the reduced pattern set. ;;; The extended language use the following approximate grammar: ;;; pat := ( patlist ) ;;; | ?- | ?x | ;;; patlist := ( pat . patlist ) | | pat ... ;;; | ??- | ??x | ???- | ???x ;;; As it stands it is not very convenient but a good syntax, with ;;; the simplicity of the backquote facility, has yet to be invented. ;;; We nevertheless offer the three-dots convention of extend-syntax ;;; which meaning is a sequence of the preceding pattern. ;;; You can also define your own macro-patterns which are expanded before ;;; being used (see defmacro-pattern below). ;;; To define macro-pattern use the following macro: variables ;;; will be bound to the arguments of the pattern (see examples below). ;;; A macro-pattern is simply rewritten into another pattern. ;;; Extended on March 10, to recognize patterns such as: ;;; ;;; (!1 (f x) (or (^1 a) (a ^1))) ;;; (!1 a (a ?- (!2 b (d ^1 ^2) (c ^2 ^1)))) ;;;===============================================================5 ;;; Standardization of patterns (very weak for now) ;;; Usual patterns such as ?x, ?-, ??y, ??-, ???x or ???- are ;;; represented as symbols. Other choices may be taken such as ;;; making ? a macro-character. (define (term-variable? e) (and (symbol? e) (> (string-length (symbol->string e)) 1) (char=? (string-ref (symbol->string e) 0) #\?) ) ) (define (segment-variable? e) (and (symbol? e) (> (string-length (symbol->string e)) 2) (char=? (string-ref (symbol->string e) 0) #\?) (char=? (string-ref (symbol->string e) 1) #\?) ) ) (define (lispish-segment-variable? e) (and (symbol? e) (> (string-length (symbol->string e)) 3) (char=? (string-ref (symbol->string e) 0) #\?) (char=? (string-ref (symbol->string e) 1) #\?) (char=? (string-ref (symbol->string e) 2) #\?) ) ) (define (tree-variable? e) (and (symbol? e) (> (string-length (symbol->string e)) 1) (char=? (string-ref (symbol->string e) 0) #\!) ) ) (define (hole-variable? e) (and (symbol? e) (> (string-length (symbol->string e)) 1) (char=? (string-ref (symbol->string e) 0) #\^) ) ) (define (term-variable-true-name e) (let ((s (symbol->string e))) (string->symbol (substring s 1 (string-length s))) ) ) (define (segment-variable-true-name e) (let ((s (symbol->string e))) (string->symbol (substring s 2 (string-length s))) ) ) (define (tree-variable-true-name e) (let ((s (symbol->string e))) (string->symbol (substring s 1 (string-length s))) ) ) (define (hole-variable-true-name e) (let ((s (symbol->string e))) (string->symbol (substring s 1 (string-length s))) ) ) (define (lispish-segment-variable-true-name e) (let ((s (symbol->string e))) (string->symbol (substring s 3 (string-length s))) ) ) ;;;===============================================================6 ;;; The normalization of the pattern extended syntax. (define (normalize-pattern e) ((standardize-pattern e) r.macro-pattern (lambda (pattern rr) pattern) ) ) ;(define (standardize-pattern e) ; (match-case e ; ( (check macro-pattern?) (standardize-macro-pattern e) ) ; ( (quote ?-) (standardize-sexp) ) ; ( (check term-variable?) (standardize-term-variable e) ) ; ( (check atom?) (standardize-quote e) ) ; ( (any) (standardize-patterns e) ) ) ) (define (standardize-pattern e) (cond ((macro-pattern? e) (standardize-macro-pattern e)) ((eq? e '?-) (standardize-sexp)) ((term-variable? e) (standardize-term-variable e)) ((hole-variable? e) (standardize-hole-variable e)) ((vector? e) (standardize-vector e)) ((atom? e) (standardize-quote e)) (else (standardize-patterns e)) ) ) ;(define (standardize-patterns e*) ; (match-case (car e*) ; ( (quote ??-) (standardize-any (cdr e*)) ) ; ( (check segment-variable?) ; (standardize-segment-variable (car e*) (cdr e*)) ) ; ( (any) ; (standardize-cons (car e*) (cdr e*)) ) ) ) (define (standardize-patterns e*) (if (pair? e*) (cond ((macro-pattern? e*) (standardize-macro-pattern e*)) ((eq? (car e*) '??-) (standardize-any (cdr e*))) ((eq? (car e*) '???-) (standardize-lispish-any (cdr e*))) ((lispish-segment-variable? (car e*)) (standardize-lispish-segment-variable (car e*) (cdr e*)) ) ((segment-variable? (car e*)) (standardize-segment-variable (car e*) (cdr e*)) ) ((tree-variable? (car e*)) (standardize-tree-variable (car e*) (cadr e*) (caddr e*)) ) (else (standardize-cons (car e*) (cdr e*))) ) (standardize-quote e*) ) ) (define (standardize-repetition e e*) (lambda (r c) ((standardize-pattern e) r (lambda (f rr) ((standardize-patterns e*) rr (lambda (f* rrr) (let ((label (jim-gensym "g"))) (c `(times ,label (cons ,f (hole ,label ,(jim-gensym "HOLE-"))) ,f* ) rrr ) ) ) ) ) ) ) ) (define (standardize-sexp) (lambda (r c) (c `(any) r) ) ) (define (standardize-cons f f*) (if (and (pair? f*) (eq? (car f*) '...)) (standardize-repetition f (cdr f*)) (if (*prefer-xcons* 'value) (standardize-real-xcons f f*) (standardize-real-cons f f*) ) ) ) (define (make-toggle) (let ((value #f)) (lambda (msg) (case msg ((value) value) ((on) (set! value #t)) ((off) (set! value #f)))))) (define *prefer-xcons* (make-toggle)) (define (standardize-real-cons f f*) (lambda (r c) ((standardize-pattern f) r (lambda (pattern1 rr) ;;; ((standardize-patterns f*) ((standardize-pattern f*) rr (lambda (pattern2 rrr) (c `(cons ,pattern1 ,pattern2) rrr) ) ) ) ) ) ) (define (standardize-real-xcons f f*) (lambda (r c) ((standardize-patterns f*) r (lambda (pattern1 rr) ((standardize-pattern f) rr (lambda (pattern2 rrr) (c `(xcons ,pattern2 ,pattern1) rrr) ) ) ) ) ) ) (define (standardize-term-variable e) (lambda (r c) (let ((name (term-variable-true-name e))) (c `(var ,name) r) ) ) ) ;(define (standardize-term-variable e) ; (lambda (r c) ; (let ((name (term-variable-true-name e))) ; (if (eq? (lookup r name) unbound-pattern) ; (c `(ref ,name (any)) ; (extend-alist r name 'term) ) ; (c `(ref ,name) r) ) ) ) ) (define (standardize-hole-variable e) (lambda (r c) (let ((name (hole-variable-true-name e))) (c `(hole ,name ,(jim-gensym "HOLE-")) r) ) ) ) (define (standardize-quote e) (lambda (r c) (c `(quote ,e) r) ) ) (define (standardize-segment-variable e f*) (lambda (r c) (let ((name (segment-variable-true-name e))) (if (eq? (lookup r name) unbound-pattern) ((standardize-patterns f*) (extend-alist r name 'segment) (lambda (pattern rr) (let ((label (jim-gensym "g"))) (c `(ssetq-append ,name (tree ,label (cons (any) (hole ,label ,(jim-gensym "HOLE-"))) (end-ssetq ,name) ) ,pattern ) rr ) ) ) ) ((standardize-patterns f*) r (lambda (pattern rr) (c `(eval-append ,name ,pattern) rr) ) ) ) ) ) ) (define (standardize-tree-variable e f1 f2) (lambda (r c) (let ((name (tree-variable-true-name e))) ((standardize-pattern f1) (extend-alist r name 'tree) (lambda (hole-pattern rr) ((standardize-pattern f2) rr (lambda (patterns rrr) (if (> (oc-count name patterns) 1) (c `(tree ,name ,patterns ,hole-pattern) rrr) (c `(times ,name ,patterns ,hole-pattern) rrr))) ) ) ) ) ) ) (define (oc-count name pattern) (cond ((null? pattern) 0) ((eq? (car pattern) 'hole) (if (eq? (cadr pattern) name) 1 0)) ((memq (car pattern) '(or and t-or tagged-or cons not)) (apply + (map (lambda (pat) (oc-count name pat)) (cdr pattern)))) (else 0))) (define (standardize-lispish-segment-variable e f*) (if (null? f*) (lambda (r c) (let ((name (lispish-segment-variable-true-name e))) (if (eq? (lookup r name) unbound-pattern) (c `(var ,name (any)) (extend-alist r name 'segment) ) (c `(var ,name) r) ) ) ) (standardize-segment-variable e f*) ) ) (define (standardize-any f*) (lambda (r c) ((standardize-patterns f*) r (lambda (pattern rr) (let ((label (jim-gensym "g"))) (if (*prefer-xcons* 'value) (c `(times ,label (xcons (any) (hole ,label ,(jim-gensym "HOLE-"))) ,pattern ) rr ) (c `(times ,label (cons (any) (hole ,label ,(jim-gensym "HOLE-"))) ,pattern ) rr ) ) ) ) ) ) ) (define (standardize-lispish-any f*) (if (null? f*) (lambda (r c) (c `(any) r)) (standardize-any f*) ) ) (define (standardize-macro-pattern e) (apply (lookup r.macro-pattern (car e)) (cdr e)) ) ;;;--------------------------------------------------------------------*/ ;;; Macro-patterns */ ;;;--------------------------------------------------------------------*/ ;;; The environment binding name to macro-pattern (define r.macro-pattern.init '()) (define r.macro-pattern r.macro-pattern.init) (define (extend-alist fn pt im) (cons (cons pt im) fn) ) (define (lookup r n) (if (assq n r) (cdr (assq n r)) #f)) (define (extend.r.macro-env name fun) (set! r.macro-pattern (extend-alist r.macro-pattern name fun))) (define-macro (defmacro-pattern name variables body) `(begin ;* (set! r.macro-pattern */ ;* (extend-alist r.macro-pattern */ ;* ',name */ ;* (lambda ,variables ,body) ) ) */ (extend.r.macro-env ',name (lambda ,variables ,body)) ',name ) ) (define (macro-pattern? e) (and (pair? e) (lookup r.macro-pattern (car e)) ) ) (defmacro-pattern atom (e . e*) (lambda (r c) (if (pair? e*) (match-wrong "Too many patterns provided for atom") ((standardize-pattern e) r (lambda (pattern rr) (c `(and (not (cons (any) (any))) ,pattern) rr)))))) (defmacro-pattern or (e . e*) (lambda (r c) (if (pair? e*) ((standardize-pattern e) r (lambda (pattern1 rr) ((standardize-pattern `(or . ,e*)) r (lambda (pattern2 rrr) (if (and (coherent-environment? rr rrr) (coherent-environment? rrr rr)) (c `(or ,pattern1 ,pattern2) rrr) (match-wrong "Incompatible alternative")))))) ((standardize-pattern e) r c)))) ;;; (defmacro-pattern tagged-or (e l . e*) */ ;;; (lambda (r c) */ ;;; (if (pair? e*) */ ;;; ((standardize-pattern e) */ ;;; r */ ;;; (lambda (pattern1 rr) */ ;;; ((standardize-pattern `(tagged-or . ,e*)) */ ;;; r */ ;;; (lambda (pattern2 rrr) */ ;;; (if (and (coherent-environment? rr rrr) */ ;;; (coherent-environment? rrr rr)) */ ;;; (c `(tagged-or ,pattern1 ,l ,pattern2) rrr) */ ;;; (match-wrong "Incompatible alternative")))))) */ ;;; ((standardize-pattern e) r c) ) ) ) */ (defmacro-pattern t-or (e . e*) (lambda (r c) (if (pair? e*) ((standardize-pattern e) r (lambda (pattern1 rr) ((standardize-pattern `(t-or . ,e*)) r (lambda (pattern2 rrr) (if (and (coherent-environment? rr rrr) (coherent-environment? rrr rr)) (c `(t-or ,pattern1 ,pattern2) rrr) (match-wrong "Incompatible alternative")))))) ((standardize-pattern e) r c) ) ) ) (defmacro-pattern and (e . e*) (lambda (r c) (if (pair? e*) ((standardize-pattern e) r (lambda (pattern1 rr) ((standardize-pattern `(and . ,e*)) rr (lambda (pattern2 rrr) (c `(and ,pattern1 ,pattern2) rrr) ) ) ) ) ((standardize-pattern e) r c)))) (defmacro-pattern not (e) (lambda (r c) ((standardize-pattern e) r (lambda (pattern rr) (c `(not ,pattern) r) ) ) ) ) (defmacro-pattern ? (e) (lambda (r c) (c `(check ,e) r))) (defmacro-pattern kwote (e) (lambda (r c) (c `(quote ,e) r))) ;;; check coherency between arms of alternative patterns: ;;; For instance (match-lambda (or ?x ?y) t) is not coherent ;;; while (match-lambda (or (?x ?y) (?y ?x)) t) is coherent. (define (coherent-environment? r rr) (labels ((look (n r) (and (pair? r) (or (eq? (caar r) n) (look n (cdr r)) ) ) )) (if (pair? r) (and (look (caar r) rr) (coherent-environment? (cdr r) rr) ) #t ) ) ) ;;;===============================================================8 ;;; report an error (implementation dependent) (define unbound-pattern '**Bad-Luck096561123523452**) (define (match-wrong . args) (error 'Pattern-Matching "ERREUR: "args)) (define (r9.init n) unbound-pattern) (define n normalize-pattern) ;;;--------------------------------------------------------------------*/ ;;; Extension to vectors (J.M. Geffroy) */ ;;;--------------------------------------------------------------------*/ (define (standardize-vector e) ; e is known to be a vector (let ((tmp (normalize-pattern (vector->list e)))) (labels ((vectorify (p) (cond ((eq? (car p) 'cons) `(vector-cons ,(cadr p) ,(if (equal? (caddr p) '(any)) '(vector-any) (vectorify (caddr p))))) ((equal? p '(quote ())) '(vector-end)) ((memq (car p) '(and or not)) (list (car p) (vectorify (cadr p)) (vectorify (caddr p)))) ((memq (car p) '(times tree)) (list 'vector-times (cadr p) (vectorify (caddr p)) (vectorify (cadddr p)))) (else p)))) (lambda (r c) (c `(vector-begin ,(pattern-length (vector->list e)) ,(vectorify tmp)) r) ) ) ) ) (define (pattern-length p) (cond ((atom? p) 0) ((null? p) 0) ((eq? (car p) 'not) 1) ((tree-variable? (car p)) 0) ((memq (car p) '(??- ???-)) 0) ((memq (car p) '(or and t-or tagged-or)) (pattern-length (cadr p))) (else (+ 1 (pattern-length (cdr p)))))) ;*---------------------------------------------------------------------*/ ;* XXX-match-define-structure! updates a global environment */ ;* mapping structure names to their lists of fields: */ ;* ((2D-point x y) (3D-point x y z)) */ ;*---------------------------------------------------------------------*/ #|STk (define *Match-Structures* '()) (define (match-define-structure! exp) (match-case exp ((define-struct ?name . ?fields) (set! *Match-Structures* (cons (cdr exp) *Match-Structures*))) (else (error "Incorrect declaration: " exp 'Aborted)))) (defmacro-pattern struct-pat (name . e*) (lambda (r c) (c `(struct-pat ,name ,@(map normalize-pattern e*)) r))) (defmacro-pattern _structure_ f (lambda (r c) (define (look-for-structure provided-fields) (let loop1 ((S *Match-Structures*)) (let loop2 ((p-f provided-fields)) (if (null? S) (error "No such structure: " provided-fields '()) (if (null? p-f) (car S) (if (memq (car p-f) (cdar S)) (loop2 (cdr p-f)) (loop1 (cdr S)))))))) (let* (;; On recupere le nom et la liste des champs ;; dans le bon ordre (structure (if (pair? (car f)) (look-for-structure (map car (cdr f))) (if (assoc (car f) *Match-Structures*) (assoc (car f) *Match-Structures*) (error "No such structure " f *Match-Structures*)))) (name (car structure)) (fields (cdr structure)) (provided-fields (if (pair? (car f)) f (cdr f))) ;; Les champs fournis ;; Attention: il ;; faudrait filtrer la valeur qu'on fournit ;; a l'aide du filtre specifie lors de la ;; declaration de la structure... (pattern `(struct-pat ,name ,@(if (pair? (car f)) (map (lambda (field) (if (assoc field provided-fields) (cadr (assoc field provided-fields)) '?-)) fields) (cdr f))))) ((standardize-pattern pattern) r c)))) |#