;;; Description: Convert algdata & synonym from ast to definition form. ;;; Lots of error checking. ;;; Algdata: ;;; Errors detected: ;;; Types & classes (deriving & context) resolved ;;; context tyvars must be parameters ;;; all parameter tyvars must be referenced ;;; only parameter tyvars must be referenced (define (algdata->def data-decl) (remember-context data-decl (with-slots data-decl (context simple constrs deriving annotations) data-decl (let* ((def (tycon-def simple)) (tyvars (simple-tyvar-list simple)) (enum? '#t) (tag 0) (derived-classes '()) (tyvars-referenced '()) (all-con-vars '()) (all-strict? (process-alg-strictness-annotation annotations)) (constr-defs (map (lambda (constr) (with-slots constr (constructor types) constr (let ((constr-def (con-ref-con constructor)) (c-arity (length types)) (con-vars '()) (all-types '()) (strictness '())) (when (not (eqv? c-arity 0)) (setf enum? '#f)) (dolist (type types) (let* ((ty (tuple-2-1 type)) (anns (tuple-2-2 type)) (tyvars1 (resolve-type ty))) (push ty all-types) (push (get-constr-strictness anns all-strict?) strictness) (dolist (v tyvars1) (if (not (memq v tyvars)) (signal-bad-algdata-tyvar v))) (setf con-vars (append tyvars1 tyvars-referenced)) (setf tyvars-referenced (append tyvars1 tyvars-referenced)))) (push (tuple constr con-vars) all-con-vars) (update-slots con constr-def (arity c-arity) (types (reverse all-types)) (tag tag) (alg def) (infix? (con-ref-infix? constructor)) (slot-strict? (reverse strictness))) (incf tag) constr-def))) constrs))) (dolist (class deriving) (if (eq? (class-ref-name class) '|Printers|) (setf (class-ref-class class) *printer-class*) (resolve-class class)) (when (not (eq? (class-ref-class class) *undefined-def*)) (push (class-ref-class class) derived-classes))) (when (not (null? constrs)) (dolist (tyvar tyvars) (when (not (memq tyvar tyvars-referenced)) (signal-unreferenced-tyvar-arg tyvar)))) (resolve-signature-aux tyvars context) ;; This computes a signature for the datatype as a whole. (let ((gtype (ast->gtype context simple))) ;; This sets the signatures for the constructors (dolist (con constr-defs) (let* ((con-type (**arrow-type/l (append (con-types con) (list simple)))) (con-context (restrict-context context (tuple-2-2 (assq con all-con-vars)))) (con-signature (ast->gtype con-context con-type))) (setf (con-signature con) con-signature))) (update-slots algdata def (n-constr (length constrs)) (constrs constr-defs) (context context) (tyvars tyvars) (signature gtype) (classes '()) (enum? enum?) (tuple? (and (not (null? constrs)) (null? (cdr constrs)))) (real-tuple? '#f) (deriving derived-classes) )) (process-alg-annotations def) def)))) (define (process-alg-strictness-annotation anns) (let ((res '#f)) (dolist (a anns) (if (and (annotation-value? a) (eq? (annotation-value-name a) '|STRICT|) (null? (annotation-value-args a))) (setf res '#t) (signal-unknown-annotation a))) res)) (define (get-constr-strictness anns all-strict?) (let ((res all-strict?)) (dolist (a anns) (cond ((annotation-value? a) (if (and (eq? (annotation-value-name a) '|STRICT|) (null? (annotation-value-args a))) (setf res '#t) (signal-unknown-annotation a))) (else (signal-unknown-annotation a)))) res)) (define (process-alg-annotations alg) (dolist (a (module-annotations *module*)) (when (and (annotation-value? a) (or (eq? (annotation-value-name a) '|ImportLispType|) (eq? (annotation-value-name a) '|ExportLispType|)) (assq (def-name alg) (car (annotation-value-args a)))) (if (eq? (annotation-value-name a) '|ImportLispType|) (setf (algdata-implemented-by-lisp? alg) '#t) (setf (algdata-export-to-lisp? alg) '#t)) (let ((constrs (tuple-2-2 (assq (def-name alg) (car (annotation-value-args a)))))) (dolist (c constrs) (process-annotated-constr alg (lookup-alg-constr (tuple-2-1 c) (algdata-constrs alg)) (tuple-2-2 c))))))) (define (lookup-alg-constr name constrs) (if (null? constrs) (fatal-error 'bad-constr-name "Constructor ~A not in algdata~%" name) (if (eq? name (def-name (car constrs))) (car constrs) (lookup-alg-constr name (cdr constrs))))) (define (process-annotated-constr alg con lisp-fns) ;; For nullary tuples, allow a single annotation to represent a constant ;; and generate the test function by default. (when (and (eqv? (con-arity con) 0) lisp-fns (null? (cdr lisp-fns))) (push `(lambda (x) (eq? x ,(car lisp-fns))) lisp-fns)) ;; Insert an implicit test function for tuples (never used anyway!) (when (and (algdata-tuple? alg) (eqv? (+ 1 (con-arity con)) (length lisp-fns))) (push '(lambda (x) '#t) lisp-fns)) (when (or (not (null? (con-lisp-fns con))) (not (eqv? (length lisp-fns) (+ 2 (con-arity con))))) (fatal-error 'bad-constr-annotation "Bad annotation for ~A in ~A~%" con alg)) (setf (con-lisp-fns con) lisp-fns)) (define (signal-unknown-annotation a) (recoverable-error 'bad-annotation "Bad or misplaced annotation: ~A%" a)) (define (restrict-context context vars) (if (null? context) '() (let ((rest (restrict-context (cdr context) vars))) (if (memq (context-tyvar (car context)) vars) (cons (car context) rest) rest)))) (define (signal-bad-algdata-tyvar tyvar) (phase-error 'bad-algdata-tyvar "~a is referenced on the right-hand side of a data type declaration,~%~ but is not bound as a type variable." tyvar)) (define (signal-unreferenced-tyvar-arg tyvar) (phase-error 'unreferenced-tyvar-arg "~a is bound as a type variable in a data type declaration,~%~ but is not referenced on the right-hand side." tyvar)) ;;; Synonyms ;;; Errors detected: (define (synonym->def synonym-decl) (remember-context synonym-decl (with-slots synonym-decl (simple body) synonym-decl (let* ((def (tycon-def simple)) (tyvars (simple-tyvar-list simple)) (tyvars-referenced (resolve-type body))) (dolist (v tyvars) (if (not (memq v tyvars-referenced)) (signal-unreferenced-synonym-arg v))) (dolist (v tyvars-referenced) (if (not (memq v tyvars)) (signal-bad-synonym-tyvar v))) (update-slots synonym def (args tyvars) (body body)) (push (cons def (gather-synonyms body '())) *synonym-refs*) def)))) (define (signal-bad-synonym-tyvar tyvar) (phase-error 'bad-synonym-tyvar "~a is referenced on the right-hand side of a type synonym declaration,~%~ but is not bound as a type variable." tyvar)) (define (signal-unreferenced-synonym-arg tyvar) (haskell-warning 'unreferenced-synonym-arg "~a is bound as a type variable in a type synonym declaration,~%~ but is not referenced on the right-hand side." tyvar)) (define (gather-synonyms type acc) (cond ((tyvar? type) acc) ((and (synonym? (tycon-def type)) (eq? *unit* (def-unit (tycon-def type)))) (gather-synonyms/list (tycon-args type) (cons (tycon-def type) acc))) (else (gather-synonyms/list (tycon-args type) acc)))) (define (gather-synonyms/list types acc) (if (null? types) acc (gather-synonyms/list (cdr types) (gather-synonyms (car types) acc))))