summaryrefslogtreecommitdiff
path: root/tdecl
diff options
context:
space:
mode:
Diffstat (limited to 'tdecl')
-rw-r--r--tdecl/README2
-rw-r--r--tdecl/alg-syn.scm228
-rw-r--r--tdecl/class.scm258
-rw-r--r--tdecl/instance.scm296
-rw-r--r--tdecl/tdecl-utils.scm16
-rw-r--r--tdecl/tdecl.scm18
-rw-r--r--tdecl/type-declaration-analysis.scm72
7 files changed, 890 insertions, 0 deletions
diff --git a/tdecl/README b/tdecl/README
new file mode 100644
index 0000000..62e6b0a
--- /dev/null
+++ b/tdecl/README
@@ -0,0 +1,2 @@
+This directory contains code to convert type-related declarations to
+definition form.
diff --git a/tdecl/alg-syn.scm b/tdecl/alg-syn.scm
new file mode 100644
index 0000000..b128486
--- /dev/null
+++ b/tdecl/alg-syn.scm
@@ -0,0 +1,228 @@
+
+;;; 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))))
diff --git a/tdecl/class.scm b/tdecl/class.scm
new file mode 100644
index 0000000..c95bbc2
--- /dev/null
+++ b/tdecl/class.scm
@@ -0,0 +1,258 @@
+;;; Before classes are converted, the super class relation is computed.
+;;; This sets up the super and super* field of each class and
+;;; checks for the following errors:
+;;; Wrong tyvar in context
+;;; cyclic class structure
+;;; Non-class in context
+
+(define (compute-super-classes modules)
+ (let ((all-classes '()))
+ (walk-modules modules
+ (lambda ()
+ (dolist (c (module-classes *module*))
+ (remember-context c
+ (with-slots class-decl (super-classes class class-var) c
+ (let* ((def (class-ref-class class))
+ (local-ctxts '())
+ (super '()))
+ (dolist (context super-classes)
+ (with-slots context (class tyvar) context
+ (when (not (eq? class-var tyvar))
+ (signal-super-class-tyvar-error class class-var tyvar))
+ (resolve-class class)
+ (let ((super-def (class-ref-class class)))
+ (when (not (eq? super-def *undefined-def*))
+ (push super-def super)
+ (when (eq? *unit* (def-unit super-def))
+ (push super-def local-ctxts))))))
+ (update-slots class def
+ (super super)
+ (tyvar class-var))
+ (push (cons def local-ctxts) all-classes)))))))
+ (multiple-value-bind (status sorted) (topsort all-classes)
+ (when (eq? status 'cyclic)
+ (signal-cyclic-class-structure sorted))
+ (dolist (c sorted)
+ (let* ((super (class-super c))
+ (super* super))
+ (dolist (s super)
+ (setf super* (set-union super* (class-super* s)))
+ (setf (class-super* c) super*)))))))
+
+(define (signal-super-class-tyvar-error class class-var tyvar)
+ (recoverable-error 'super-class-tyvar-error
+ "The context for class ~A must only refer to type variable ~A.~%~
+ Type variable ~A cannot be used here."
+ (class-ref-name class) class-var tyvar))
+
+(define (signal-cyclic-class-structure classes)
+ (fatal-error 'cyclic-class-structure
+ "There is a cycle in the superclass relation involving these classes:~%~a"
+ classes))
+
+
+;;; This sets up the following fields in the class entry:
+;;; instances '()
+;;; defaults = ast for defaults
+;;; kind
+;;; methods
+;;; signatures
+;;; method-vars
+;;; selectors
+;;; Each method is initialized with
+;;; class
+;;; signature
+;;; type
+;;; Errors detected:
+;;; signature doesnt reference class
+
+(define (class->def class-decl)
+ (remember-context class-decl
+ (let* ((class (class-ref-class (class-decl-class class-decl)))
+ (decls (class-decl-decls class-decl)))
+ (setf (class-instances class) '())
+ (setf (class-kind class) (find-class-kind class))
+ (init-methods class decls) ; sets up defaults, method signatures
+ (setf (class-n-methods class) (length (class-method-vars class)))
+ (setf (class-dict-size class)
+ (+ (class-n-methods class) (length (class-super* class))))
+ class)))
+
+(define (find-class-kind class)
+ (cond ((not (module-prelude? *module*))
+ 'other)
+ ((memq class
+ (list (core-symbol "Eq") (core-symbol "Ord")
+ (core-symbol "Text") (core-symbol "Binary")
+ (core-symbol "Ix") (core-symbol "Enum")))
+ 'Standard)
+ ((memq class
+ (list (core-symbol "Num") (core-symbol "Real")
+ (core-symbol "Integral") (core-symbol "Fractional")
+ (core-symbol "Floating") (core-symbol "RealFrac")
+ (core-symbol "RealFloat")))
+ 'Numeric)
+ (else
+ 'other)))
+
+(define (init-methods class decls)
+ (let* ((tyvar (class-tyvar class))
+ (class-context (**context (**class/def class) tyvar)))
+ (dolist (decl decls)
+ (remember-context decl
+ (cond ((is-type? 'signdecl decl)
+ (let* ((signature (signdecl-signature decl))
+ (vars (resolve-signature signature)))
+ (when (not (memq tyvar vars))
+ (signal-class-sig-ignores-type signature))
+ ;; Note: signature does not include defined class yet
+ (dolist (context (signature-context signature))
+ (when (eq? tyvar (context-tyvar context))
+ (signal-method-constrains-class-tyvar context)))
+ (setf signature (rename-class-sig-vars signature tyvar))
+ (let ((gtype (ast->gtype (cons class-context
+ (signature-context signature))
+ (signature-type signature))))
+ (dolist (var-ref (signdecl-vars decl))
+ (let ((var (var-ref-var var-ref)))
+ (setf (var-type var) gtype)
+ (setf (method-var-method-signature var) signature))))))
+ (else ; decl must be a default definition
+ (let ((vars (collect-pattern-vars (valdef-lhs decl))))
+ (dolist (var-ref vars)
+ (resolve-var var-ref)
+ (let* ((method-name (var-ref-name var-ref))
+ (method-var (var-ref-var var-ref)))
+ (when (not (eq? method-var *undefined-def*))
+ (if (and (method-var? method-var)
+ (eq? (method-var-class method-var) class))
+ (let ((default-var
+ (make-new-var
+ (string-append
+ "default-"
+ (symbol->string (def-name method-var))))))
+ (setf (var-ref-var var-ref) default-var)
+ (setf (var-ref-name var-ref) (def-name default-var))
+ (when (not (eq? (method-var-default method-var) '#f))
+ (signal-multiple-definition-of-default method-name))
+ (setf (method-var-default method-var) default-var)
+ (let* ((sig (method-var-method-signature method-var))
+ (context (cons class-context
+ (signature-context sig)))
+ (new-sig (**signature context
+ (signature-type sig))))
+ (add-new-module-signature default-var new-sig)))
+ (signal-default-not-in-class method-var class)))))
+ (add-new-module-decl decl))))))))
+
+(define (signal-class-sig-ignores-type signature)
+ (phase-error 'class-sig-ignores-type
+ "The method signature ~a does not reference the overloaded type."
+ signature))
+
+
+;;; *** I don't understand this message.
+
+(define (signal-method-constrains-class-tyvar context)
+ (phase-error 'method-constrains-class-tyvar
+ "Individual methods may not further constrain a class: ~A" context))
+
+
+;;; *** I don't understand this message.
+
+(define (signal-multiple-definition-of-default method-name)
+ (phase-error 'multiple-definition-of-default
+ "More that one default for ~A."
+ method-name))
+
+
+;;; *** I don't understand this message.
+
+(define (signal-default-not-in-class method-var class)
+ (phase-error 'default-not-in-class
+ "~A is not a method in class ~A."
+ method-var class))
+
+
+(define (create-selector-functions class)
+ (let ((res '()))
+ (dolist (c (cons class (class-super* class)))
+ (dolist (m (class-method-vars c))
+ (let* ((var (make-new-var
+ (string-append "sel-"
+ (symbol->string (def-name class))
+ "/"
+ (symbol->string (def-name m)))))
+ (sel-body (create-selector-code class m)))
+ (setf (var-selector-fn? var) '#t)
+ (push (tuple m var) res)
+ (when (not (eq? (module-type *module*) 'interface))
+ (add-new-module-def var sel-body)))))
+ res))
+
+(define (create-selector-code c m)
+ (let ((var (create-local-definition '|d|)))
+ (setf (var-force-strict? var) '#t)
+ (let ((body (create-selector-code-1 c m (**var/def var))))
+ (**lambda/pat (list (**var-pat/def var)) body))))
+
+(define (create-selector-code-1 class method d)
+ (let ((mcl (method-var-class method)))
+ (cond ((eq? mcl class)
+ (**dsel/method class method d))
+ (else
+ (**dsel/method mcl method (**dsel/dict class mcl d))))))
+
+;;; The following code is for the alpha conversion of method
+;;; signatures. The class tyvar is unchanged; all others are renamed.
+;;; This is needed because all method types are combined to form the
+;;; dictionary signature and aliasing among different tyvars should be
+;;; prevented.
+
+(define (rename-class-sig-vars signature tyvar)
+ (mlet (((new-context env1)
+ (rename-context-vars (signature-context signature)
+ (list (tuple tyvar tyvar))))
+ ((new-type _)
+ (rename-type-vars (signature-type signature) env1)))
+ (**signature new-context new-type)))
+
+(define (rename-context-vars contexts env)
+ (if (null? contexts)
+ (values '() env)
+ (mlet (((new-tyvar env1)
+ (rename-sig-tyvar (context-tyvar (car contexts)) env))
+ ((rest env2)
+ (rename-context-vars (cdr contexts) env1)))
+ (values (cons (**context (context-class (car contexts)) new-tyvar) rest)
+ env2))))
+
+(define (rename-type-vars type env)
+ (if (tyvar? type)
+ (mlet (((tyvar env1)
+ (rename-sig-tyvar (tyvar-name type) env)))
+ (values (**tyvar tyvar) env1))
+ (mlet (((new-types env1) (rename-type-vars/l (tycon-args type) env)))
+ (values (**tycon/def (tycon-def type) new-types) env1))))
+
+(define (rename-type-vars/l types env)
+ (if (null? types)
+ (values '() env)
+ (mlet (((type1 env1) (rename-type-vars (car types) env))
+ ((new-types env2) (rename-type-vars/l (cdr types) env1)))
+ (values (cons type1 new-types) env2))))
+
+(define (rename-sig-tyvar tyvar env)
+ (let ((res (assq tyvar env)))
+ (if (eq? res '#f)
+ (let ((new-tyvar (gentyvar (symbol->string tyvar))))
+ (values new-tyvar (cons (tuple tyvar new-tyvar) env)))
+ (values (tuple-2-2 res) env))))
+
+(define *tyvar-counter* 0)
+
+;;; This generates a new interned tyvar name
+
+(define (gentyvar root)
+ (incf *tyvar-counter*)
+ (string->symbol (format '#f "~A-~A" root *tyvar-counter*)))
diff --git a/tdecl/instance.scm b/tdecl/instance.scm
new file mode 100644
index 0000000..1866339
--- /dev/null
+++ b/tdecl/instance.scm
@@ -0,0 +1,296 @@
+;;; tdecl/instance.scm
+
+;;; Convert an instance decl to a definition
+
+;;; The treatment of instances is more complex than the treatment of other
+;;; type definitions due to the possibility of derived instances.
+;;; Here's the plan:
+;;; a) instance-decls are converted to instance structures. The type
+;;; information is verified but the decls are unchanged.
+;;; b) All instances are linked into the associated classes.
+;;; c) Derived instances are generated.
+;;; d) Instance dictionaries are generated from the decls in the instances.
+;;;
+
+;;; Instances-decl to instance definition conversion
+;;; Errors detected:
+;;; Class must be a class
+;;; Data type must be an alg
+;;; Tyvars must be distinct
+;;; Correct number of tyvars
+;;; Context applies only to tyvars in simple
+;;; C-T restriction
+
+;;; Needs work for interface files.
+
+(define (instance->def inst-decl)
+ (recover-errors '#f
+ (remember-context inst-decl
+ (with-slots instance-decl (context class simple decls) inst-decl
+ (resolve-type simple)
+ (resolve-class class)
+ (let ((alg-def (tycon-def simple))
+ (class-def (class-ref-class class)))
+ (when (not (algdata? (tycon-def simple)))
+ (signal-datatype-required (tycon-def simple)))
+ (let ((tyvars (simple-tyvar-list simple)))
+ (resolve-signature-aux tyvars context)
+ (when (and (not (eq? *module-name* (def-module alg-def)))
+ (not (eq? *module-name* (def-module class-def))))
+ (signal-c-t-rule-violation class-def alg-def))
+ (let ((old-inst (lookup-instance alg-def class-def)))
+ (when (and (not (eq? old-inst '#f))
+ (not (instance-special? old-inst)))
+ (signal-multiple-instance class-def alg-def))
+ (let ((inst (new-instance class-def alg-def tyvars)))
+ (setf (instance-context inst) context)
+ (setf (instance-decls inst) decls)
+ (setf (instance-ok? inst) '#t)
+ inst))))))))
+
+(define (signal-datatype-required def)
+ (phase-error 'datatype-required
+ "The synonym type ~a cannot be declared as an instance."
+ (def-name def)))
+
+(define (signal-c-t-rule-violation class-def alg-def)
+ (phase-error 'c-t-rule-violation
+ "Instance declaration does not appear in the same module as either~%~
+ the class ~a or type ~a."
+ class-def alg-def))
+
+(define (signal-multiple-instance class-def alg-def)
+ (phase-error 'multiple-instance
+ "The type ~a has already been declared to be an instance of class ~a."
+ alg-def class-def))
+
+;;; This generates the dictionary for each instance and makes a few final
+;;; integrity checks in the instance context. This happens after derived
+;;; instances are inserted.
+
+(define (expand-instance-decls inst)
+ (when (instance-ok? inst)
+ (check-inst-type inst)
+ (with-slots instance (class algdata dictionary decls context tyvars) inst
+ (let ((simple (**tycon/def algdata (map (function **tyvar) tyvars))))
+ (setf (instance-gcontext inst)
+ (gtype-context (ast->gtype/inst context simple)))
+ (with-slots class (super* method-vars) class
+ ;; Before computing signatures uniquify tyvar names to prevent
+ ;; collision with method tyvar names
+ (let ((new-tyvars (map (lambda (tyvar) (tuple tyvar (gentyvar "tv")))
+ (instance-tyvars inst))))
+ (setf (instance-tyvars inst) (map (function tuple-2-2) new-tyvars))
+ (setf (instance-context inst)
+ (map (lambda (c)
+ (**context (context-class c)
+ (tuple-2-2 (assq (context-tyvar c) new-tyvars))))
+ (instance-context inst))))
+ ;; Now walk over the decls & rename each method with a unique name
+ ;; generated by combining the class, type, and method. Watch for
+ ;; multiple defs of methods and add defaults after all decls have
+ ;; been scanned.
+ (let ((methods-used '())
+ (new-instance-vars (map (lambda (m)
+ (tuple m (method-def-var m inst)))
+ method-vars)))
+ (dolist (decl decls)
+ (setf methods-used
+ (process-instance-decl decl new-instance-vars methods-used)))
+ ;; now add defaults when needed
+ (dolist (m-v new-instance-vars)
+ (let* ((method-var (tuple-2-1 m-v))
+ (definition-var (tuple-2-2 m-v))
+ (signature (generate-method-signature inst method-var '#t)))
+ (if (memq method-var methods-used)
+ (add-new-module-signature definition-var signature)
+ (let ((method-body
+ (if (eq? (method-var-default method-var) '#f)
+ (**abort (format '#f
+ "No method declared for method ~A in instance ~A(~A)."
+ method-var class algdata))
+ (**var/def (method-var-default method-var)))))
+ (add-new-module-def definition-var method-body)
+ (add-new-module-signature definition-var signature)))))
+ (setf (instance-methods inst) new-instance-vars)
+ (add-new-module-def dictionary
+ (**tuple/l (append (map (lambda (m-v)
+ (dict-method-ref
+ (tuple-2-1 m-v) (tuple-2-2 m-v) inst))
+ new-instance-vars)
+ (map (lambda (c)
+ (get-class-dict algdata c))
+ super*))))
+ (let ((dict-sig (generate-dictionary-signature inst)))
+ (add-new-module-signature dictionary dict-sig))
+ (setf (instance-decls inst) '())))))))
+
+(define (dict-method-ref method-var inst-var inst)
+ (if (null? (signature-context (method-var-method-signature method-var)))
+ (**var/def inst-var)
+ (let* ((sig (generate-method-signature inst method-var '#f))
+ (ctxt (signature-context sig))
+ (ty (signature-type sig)))
+ (make overloaded-var-ref
+ (sig (ast->gtype ctxt ty))
+ (var inst-var)))))
+
+(define (get-class-dict algdata class)
+ (let ((inst (lookup-instance algdata class)))
+ (if (eq? inst '#f)
+ (**abort "Missing super class")
+ (**var/def (instance-dictionary inst)))))
+
+(define (process-instance-decl decl new-instance-vars methods-used)
+ (if (valdef? decl)
+ (rename-instance-decl decl new-instance-vars methods-used)
+ (begin
+ (dolist (a (annotation-decls-annotations decl))
+ (cond ((annotation-value? a)
+ (recoverable-error 'misplaced-annotation
+ "Misplaced annotation: ~A~%" a))
+ (else
+ (dolist (name (annotation-decl-names a))
+ (attach-method-annotation
+ name (annotation-decl-annotations a) new-instance-vars)))))
+ methods-used)))
+
+(define (attach-method-annotation name annotations vars)
+ (cond ((null? vars)
+ (signal-no-method name))
+ ((eq? name (def-name (tuple-2-1 (car vars))))
+ (setf (var-annotations (tuple-2-2 (car vars)))
+ (append annotations (var-annotations (tuple-2-2 (car vars))))))
+ (else (attach-method-annotation name annotations (cdr vars)))))
+
+(define (signal-no-method name)
+ (recoverable-error 'no-method "~A is not a method in this class.~%"
+ name))
+
+(define (rename-instance-decl decl new-instance-vars methods-used)
+ (let ((decl-vars (collect-pattern-vars (valdef-lhs decl))))
+ (dolist (var decl-vars)
+ (resolve-var var)
+ (let ((method (var-ref-var var)))
+ (when (not (eq? method *undefined-def*))
+ (let ((m-v (assq method new-instance-vars)))
+ (cond ((memq method methods-used)
+ (signal-multiple-instance-def method))
+ ((eq? m-v '#f)
+ (signal-not-in-class method))
+ (else
+ (setf (var-ref-name var) (def-name (tuple-2-2 m-v)))
+ (setf (var-ref-var var) (tuple-2-2 m-v))
+ (push (tuple-2-1 m-v) methods-used)))))))
+ (add-new-module-decl decl)
+ methods-used))
+
+(define (signal-multiple-instance-def method)
+ (phase-error 'multiple-instance-def
+ "The instance declaration has multiple definitions of the method ~a."
+ method))
+
+(define (signal-not-in-class method)
+ (phase-error 'not-in-class
+ "The instance declaration includes a definition for ~a,~%~
+ which is not one of the methods for this class."
+ method))
+
+
+(define (method-def-var method-var inst)
+ (make-new-var
+ (string-append "i-"
+ (symbol->string (print-name (instance-class inst))) "-"
+ (symbol->string (print-name (instance-algdata inst))) "-"
+ (symbol->string (def-name method-var)))))
+
+(define (generate-method-signature inst method-var keep-method-context?)
+ (let* ((simple-type (make-instance-type inst))
+ (class-context (instance-context inst))
+ (class-tyvar (class-tyvar (instance-class inst)))
+ (signature (method-var-method-signature method-var)))
+ (make signature
+ (context (if keep-method-context?
+ (append class-context (signature-context signature))
+ class-context))
+ (type (substitute-tyvar (signature-type signature) class-tyvar
+ simple-type)))))
+
+(define (make-instance-type inst)
+ (**tycon/def (instance-algdata inst)
+ (map (function **tyvar) (instance-tyvars inst))))
+
+(define (generate-dictionary-signature inst)
+ (**signature (sort-inst-context-by-tyvar
+ (instance-context inst) (instance-tyvars inst))
+ (generate-dictionary-type inst (make-instance-type inst))))
+
+(define (sort-inst-context-by-tyvar ctxt tyvars)
+ (concat (map (lambda (tyvar)
+ (extract-single-context tyvar ctxt)) tyvars)))
+
+(define (extract-single-context tyvar ctxt)
+ (if (null? ctxt)
+ '()
+ (let ((rest (extract-single-context tyvar (cdr ctxt))))
+ (if (eq? tyvar (context-tyvar (car ctxt)))
+ (cons (car ctxt) rest)
+ rest))))
+
+(define (generate-dictionary-type inst simple)
+ (let* ((class (instance-class inst))
+ (algdata (instance-algdata inst))
+ (tyvar (class-tyvar class)))
+ (**tuple-type/l (append (map (lambda (method-var)
+ ;; This ignores the context associated
+ ;; with a method
+ (let ((sig (method-var-method-signature
+ method-var)))
+ (substitute-tyvar (signature-type sig)
+ tyvar
+ simple)))
+ (class-method-vars class))
+ (map (lambda (super-class)
+ (generate-dictionary-type
+ (lookup-instance algdata super-class)
+ simple))
+ (class-super* class))))))
+
+;;; Checks performed here:
+;;; Instance context must include the following:
+;;; Context associated with data type
+;;; Context associated with instances for each super class
+;;; All super class instances must exist
+
+(define (check-inst-type inst)
+ (let* ((class (instance-class inst))
+ (algdata (instance-algdata inst))
+ (inst-context (instance-gcontext inst))
+ (alg-context (gtype-context (algdata-signature algdata))))
+ (when (not (full-context-implies? inst-context alg-context))
+ (signal-instance-context-needs-alg-context algdata))
+ (dolist (super-c (class-super class))
+ (let ((super-inst (lookup-instance algdata super-c)))
+ (cond ((eq? super-inst '#f)
+ (signal-no-super-class-instance class algdata super-c))
+ (else
+ (when (not (full-context-implies?
+ inst-context (instance-context super-inst)))
+ (signal-instance-context-insufficient-for-super
+ class algdata super-c))))))
+ ))
+
+(define (signal-instance-context-needs-alg-context algdata)
+ (phase-error 'instance-context-needs-alg-context
+ "The instance context needs to include context defined for data type ~A."
+ algdata))
+
+(define (signal-no-super-class-instance class algdata super-c)
+ (fatal-error 'no-super-class-instance
+ "The instance ~A(~A) requires that the instance ~A(~A) be provided."
+ class algdata super-c algdata))
+
+(define (signal-instance-context-insufficient-for-super class algdata super-c)
+ (phase-error 'instance-context-insufficient-for-super
+ "Instance ~A(~A) does not imply super class ~A instance context."
+ class algdata super-c))
diff --git a/tdecl/tdecl-utils.scm b/tdecl/tdecl-utils.scm
new file mode 100644
index 0000000..0009eeb
--- /dev/null
+++ b/tdecl/tdecl-utils.scm
@@ -0,0 +1,16 @@
+;;; This file contains routines which generate the code for the
+;;; dictionaries used in the class system.
+
+(define (make-sel-node size i)
+ (**lambda '(x)
+ (if (eqv? size 1)
+ (**var 'x)
+ (**sel (tuple-constructor size) (**var 'x) i))))
+
+(define (make-compose f1 f2)
+ (**lambda '(x)
+ (**app f1 (**app f2 (**var 'x)))))
+
+(define (make-new-var name) ; name is a string
+ (create-definition *module* (string->symbol name) 'var))
+
diff --git a/tdecl/tdecl.scm b/tdecl/tdecl.scm
new file mode 100644
index 0000000..227171e
--- /dev/null
+++ b/tdecl/tdecl.scm
@@ -0,0 +1,18 @@
+;;; -- compilation unit definition for type declaration analysis
+;;;
+;;; author : John
+;;;
+
+(define-compilation-unit tdecl
+ (source-filename "$Y2/tdecl/")
+ (require global)
+ (unit type-declaration-analysis
+ (source-filename "type-declaration-analysis.scm"))
+ (unit tdecl-utils
+ (source-filename "tdecl-utils.scm"))
+ (unit alg-syn
+ (source-filename "alg-syn.scm"))
+ (unit class
+ (source-filename "class.scm"))
+ (unit instance
+ (source-filename "instance.scm")))
diff --git a/tdecl/type-declaration-analysis.scm b/tdecl/type-declaration-analysis.scm
new file mode 100644
index 0000000..bffcb23
--- /dev/null
+++ b/tdecl/type-declaration-analysis.scm
@@ -0,0 +1,72 @@
+;;; This processes type declarations (data, type, instance, class)
+;;; Static errors in type declarations are detected and type decls
+;;; are replaced by type definitions. All code (class and instance
+;;; definitions) is moved to the module decls.
+
+(define *synonym-refs* '())
+
+(predefine (add-derived-instances modules)) ; in derived/derived-instances.scm
+
+(define (process-type-declarations modules)
+;;; Convert data & type decls to definitions
+ (let ((interface? (eq? (module-type (car modules)) 'interface)))
+ (setf *synonym-refs* '())
+ (walk-modules modules
+ (lambda ()
+ (setf (module-alg-defs *module*)
+ (map (function algdata->def) (module-algdatas *module*)))
+ (setf (module-synonym-defs *module*)
+ (map (function synonym->def) (module-synonyms *module*)))
+ (when (not interface?)
+ (dolist (ty (default-decl-types (module-default *module*)))
+ (resolve-type ty))))
+ ;; A test to see that ty is in Num and is a monotype is needed here.
+ )
+ (multiple-value-bind (ty vals) (topsort *synonym-refs*)
+ (when (eq? ty 'cyclic) (signal-recursive-synonyms vals)))
+ ;; Build the class heirarchy
+ (compute-super-classes modules)
+ ;; Convert class declarations and instance declarations to definitions.
+ (walk-modules modules
+ (lambda ()
+ (setf (module-class-defs *module*)
+ (map (function class->def) (module-classes *module*)))))
+ (walk-modules modules
+ (lambda ()
+ (dolist (class (module-class-defs *module*))
+ (setf (class-selectors class) (create-selector-functions class)))))
+ (walk-modules modules
+ (lambda ()
+ (setf (module-instance-defs *module*) '())
+ (dolist (inst-decl (module-instances *module*))
+ (let ((inst (instance->def inst-decl)))
+ (when (not (eq? inst '#f))
+ (push inst (module-instance-defs *module*)))))))
+ (add-derived-instances modules)
+ (walk-modules modules
+ (lambda ()
+ (dolist (inst (module-instance-defs *module*))
+ (expand-instance-decls inst))))
+ (when (not interface?)
+ (walk-modules modules
+ (lambda ()
+ (dolist (ty (default-decl-types (module-default *module*)))
+ (resolve-type ty)))))
+ ))
+
+
+(define (signal-recursive-synonyms vals)
+ (fatal-error 'recursive-synonyms
+ "There is a cycle in type synonym definitions involving these types:~%~a"
+ vals))
+
+(define (add-new-module-decl decl)
+ (setf (module-decls *module*) (cons decl (module-decls *module*))))
+
+(define (add-new-module-def var value)
+ (add-new-module-decl
+ (**define var '() value)))
+
+(define (add-new-module-signature var signature)
+ (add-new-module-decl
+ (**signdecl/def (list var) signature)))