git.fiddlerwoaroof.com
Raw Blame History
;;; File: parser/typedecl-parser     Author: John

(define (parse-type-decl interface?)
 (save-parser-context
  (let* ((sig (parse-signature))
	 (contexts (signature-context sig))
	 (simple (signature-type sig))
	 (deriving '())
	 (constrs '()))
    ;; #t = builtins ([] (,,) ->) not allowed
    (check-simple simple '#t "type declaration")
    (let ((annotations (parse-constr-annotations)))
     (token-case
      (= (setf constrs (parse-constrs))
	 (token-case
	  (|deriving|
	   (setf deriving
	     (token-case
		 (\( 
		  (token-case
		   (\) '())
		   (else (parse-class-list))))
		 (tycon (list (class->ast)))
		 (else (signal-invalid-syntax "a deriving clause")))))))
      (else
       (when (not interface?)
	 (signal-missing-constructors))))
    (make data-decl (context contexts) (simple simple)
		    (constrs constrs) (deriving deriving)
		    (annotations annotations))))))

(define (signal-missing-constructors)
  (parser-error 'missing-constructors
		"Data type definition requires constructors"))

(define (check-simple simple fresh? where)
  (when (not (tycon? simple))
    (signal-not-simple where))
  (when (and fresh? (not (eq? (tycon-def simple) *undefined-def*)))
    (signal-not-simple where))
  (let ((tyvars (map (lambda (arg)
		       (when (not (tyvar? arg))
			     (signal-not-simple where))
		       (tyvar-name arg))
		     (tycon-args simple))))
    (when (not (null? (find-duplicates tyvars)))
      (signal-unique-tyvars-required))))

(define (signal-unique-tyvars-required)
  (parser-error 'unique-tyvars-required
		"Duplicate type variables appear in simple."))

(define (signal-not-simple where)
  (parser-error 'not-simple "Simple type required in ~a." where))

(define (parse-constrs)
  (let ((constr (parse-constr)))
    (token-case
     (\| (cons constr (parse-constrs)))
     (else (list constr)))))

(define (parse-constr)
 (save-parser-context
  (let ((saved-excursion (save-scanner-state)))
    (token-case
     (consym/paren
      (parse-prefix-constr))
     (else
      (let ((type1 (parse-btype))
	    (anns (parse-constr-annotations)))
	(token-case
	 (conop
	  (parse-infix-constr (tuple type1 anns)))
	 (else
	  (restore-excursion saved-excursion)
	  (parse-prefix-constr)))))))))

(define (parse-prefix-constr)
  (token-case
   (con
    (let* ((con (con->ast))
	   (types (parse-constr-type-list)))
      (make constr (constructor con) (types types))))
   (else
    (signal-missing-token "<con>" "constrs list"))))

(define (parse-constr-type-list)
  (token-case
    (atype-start
     (let* ((atype (parse-atype))
	    (anns (parse-constr-annotations)))
       (cons (tuple atype anns)
	     (parse-constr-type-list))))
    (else '())))

(define (parse-infix-constr t+a1)
  (let* ((con (conop->ast))
	 (type2 (parse-btype))
	 (anns (parse-constr-annotations)))
    (make constr (constructor con) (types (list t+a1 (tuple type2 anns))))))

(define (parse-class-list)
  (token-case
   (tycon (let ((class (class->ast)))
	     (token-case
	      (\, (cons class (parse-class-list)))
	      (\) (list class))
	      (else (signal-missing-token "`)' or `,'" "deriving clause")))))
   (else (signal-missing-token "<tycon>" "deriving clause"))))

(define (parse-constr-annotations)
  (token-case
   ((begin-annotation no-advance)
    (let ((annotations (parse-annotations)))
      (append annotations (parse-constr-annotations))))
   (else '())))

(define (parse-synonym-decl)
 (save-parser-context
  (let* ((sig (parse-signature))
	 (contexts (signature-context sig))
	 (simple (signature-type sig)))
    (check-simple simple '#t "type synonym declaration")
    (when (not (null? contexts))
      (signal-no-context-in-synonym))
    (require-token = (signal-missing-token "`='" "type synonym declaration"))
    (let ((body (parse-type)))
      (make synonym-decl (simple simple) (body body))))))

(define (signal-no-context-in-synonym)
  (parser-error 'no-context-in-synonym
		"Context is not permitted in type synonym declaration."))

(define (parse-class-decl)
 (save-parser-context
  (let ((supers (parse-optional-context)))
    (token-case
     (tycon
      (let ((class (class->ast)))
	(token-case
	 (tyvar
	  (let* ((class-var (token->symbol))
		 (decls (parse-where-decls)))
	    (make class-decl (class class) (super-classes supers)
		             (class-var class-var) (decls decls))))
	 (else
	  (signal-missing-token "<tyvar>" "class declaration")))))
     (else (signal-missing-token "<tycon>" "class declaration"))))))

(define (parse-instance-decl interface?)
 (save-parser-context
  (let ((contexts (parse-optional-context))
	(decls '()))
    (token-case
     (tycon
      (let* ((class (class->ast))
	     (simple (parse-type)))
	(when (not interface?)
	   (setf decls (parse-where-decls)))
	(check-simple simple '#f "instance declaration")
	(make instance-decl (context contexts) (class class)
	                    (simple simple) (decls decls))))
     (else (signal-missing-token "<tycon>" "instance declaration"))))))