git.fiddlerwoaroof.com
parser/pattern-parser.scm
4e987026
 ;;;  File: pattern-parser        Author: John
 
 ;;; This parses the pattern syntax except for the parts which need to be
 ;;; resolved by precedence parsing.
 
 ;;; This parses a list of alternating pats & conops.
 
 (define (parse-pat)
  (trace-parser pat
    (let ((res (parse-pat/list)))
      (if (null? (cdr res))
 	 (car res)
 	 (make pp-pat-list (pats res))))))
 
 ;;; This parses a list of patterns with intervening conops and + patterns
 
 (define (parse-pat/list)
   (token-case
     (con (let ((pcon (pcon->ast)))
 	   (setf (pcon-pats pcon) (parse-apat-list))
 	   (cons pcon (parse-pat/tail))))
     (-n
      (advance-token) ; past -
      (token-case
       (numeric (let ((val (literal->ast)))
 		 (cons (make pp-pat-negated)
 		       (cons (make const-pat (value val))
 			     (parse-pat/tail)))))
       (else
        (signal-missing-token "<number>" "negative literal pattern"))))
     (var
      (let ((var (var->ast)))
        (token-case
 	(+k (cons (make var-pat (var var))
 		  (parse-+k-pat)))
 	(@  (let ((pattern (parse-apat)))
 	      (cons (make as-pat (var var) (pattern pattern))
 		    (parse-pat/tail))))
 	(else (cons (make var-pat (var var)) (parse-pat/tail))))))
     (_
      (let ((pat (make wildcard-pat)))
        (token-case
 	(+k (cons pat (parse-+k-pat)))
 	(else (cons pat (parse-pat/tail))))))
     (else (let ((apat (parse-apat)))
 	    (cons apat (parse-pat/tail))))))
 
 
 (define (parse-+k-pat)
   (advance-token)  ; past +
   (token-case
    (k (let ((val (literal->ast)))
 	(cons (make pp-pat-plus)
 	      (cons (make const-pat (value val))
 		    (parse-pat/tail)))))
    (else (signal-missing-token "<integer>" "successor pattern"))))
 
 (define (parse-pat/tail)
    (token-case
      (conop
       (let ((con (pconop->ast)))
 	(cons con (parse-pat/list))))
      (else '())))
 
 (define (parse-apat)
  (trace-parser apat
    (token-case
      (var (let ((var (var->ast)))
 	    (token-case
 	     (@
 	      (let ((pattern (parse-apat)))
 		(make as-pat (var var) (pattern pattern))))
 	     (else (make var-pat (var var))))))
      (con (pcon->ast))
      (literal (let ((value (literal->ast)))
 		(make const-pat (value value))))
      (_ (make wildcard-pat))
      (\( (token-case
            (\) (**pcon/def (core-symbol "UnitConstructor") '()))
 	   (else
 	    (let ((pat (parse-pat)))
 	      (token-case
 		(\, (**pcon/tuple (cons pat (parse-pat-list '\)))))
 		(\) pat)
 		(else
 		 (signal-missing-token "`)' or `,'" "pattern")))))))
      (\[ (token-case
 	  (\] (make list-pat (pats '())))
 	  (else (make list-pat (pats (parse-pat-list '\]))))))
      (\~ (let ((pattern (parse-apat)))
 	   (make irr-pat (pattern pattern))))
      (else
       (signal-invalid-syntax "an apat")))))
 
 (define (parse-pat-list term)  ;; , separated
   (let ((pat (parse-pat)))
     (token-case
      (\, (cons pat (parse-pat-list term)))
      ((unquote term) (list pat))
      (else
       (signal-missing-token
         (if (eq? term '\)) "`)'" "`]'")
 	"pattern")))))
 
 (define (parse-apat-list)  ;; space separated
   (token-case
     (apat-start
      (let ((pat (parse-apat)))
        (cons pat (parse-apat-list))))
     (else
      '())))
 
 ;;; The following routine scans patterns without creating ast structure.
 ;;; They return #t or #f depending on whether a valid pattern was encountered.
 ;;; The leave the scanner pointing to the next token after the pattern.
 
 (define (scan-pat)  ; same as parse-pat/list
   (and
    (token-case
     (con (scan-con)
 	 (scan-apat-list))
     (-n (advance-token)
 	(token-case
 	 (numeric (advance-token)
 		  '#t)
 	 (else '#f)))
     (var (and (scan-var)
 	      (token-case
 	       (@ (scan-apat))
 	       (+k (scan-+k))
 	       (else '#t))))
     (_ (scan-+k))
     (else (scan-apat)))
    (scan-pat/tail)))
 
 (define (scan-pat/tail)
   (token-case
    (conop (and (scan-conop)
 	       (scan-pat)))
    (else '#t)))
 
 (define (scan-apat)
   (token-case
    (var (scan-var)
 	(token-case
 	 (@ (scan-apat))
 	 (else '#t)))
    (con (scan-con))
    (literal (advance-token)
 	    '#t)
    (_ '#t)
    (\( (token-case
 	(\) '#t)
 	(else
 	 (and (scan-pat)
 	      (token-case
 	       (\, (scan-pat-list '\)))
 	       (\) '#t)
 	       (else '#f))))))
    (\[ (token-case
 	(\] '#t)
 	(else (scan-pat-list '\]))))
    (\~ (scan-apat))
    (else '#f)))
 
 (define (scan-pat-list term)
   (and (scan-pat)
        (token-case
 	(\, (scan-pat-list term))
 	((unquote term) '#t)
 	(else '#f))))
 
 (define (scan-apat-list)
   (token-case
    (apat-start
     (and (scan-apat)
 	 (scan-apat-list)))
    (else '#t)))
 
 (define (scan-var)
   (token-case
    (varid '#t)
    (\( (token-case
 	(varsym
 	 (token-case
 	  (\) '#t)
 	  (else '#f)))
 	(else '#f)))
    (else '#f)))
 
 (define (scan-con)
   (token-case
    (conid '#t)
    (\( (token-case
 	(consym
 	 (token-case
 	  (\) '#t)
 	  (else '#f)))
 	(else '#f)))
    (else '#f)))
 
 (define (scan-conop)
   (token-case
    (consym '#t)
    (\` (token-case
 	(conid
 	 (token-case
 	  (\` '#t)
 	  (else '#f)))
 	(else '#f)))
    (else '#f)))
 
 (define (scan-+k)
   (token-case
    (+k (advance-token)  ; past the +
        (token-case
 	(integer '#t)
 	(else '#f)))
    (else '#t)))