git.fiddlerwoaroof.com
Raw Blame History
;;;  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)))