git.fiddlerwoaroof.com
infer-type.lisp
7c37909c
 (defpackage :infer-type
   (:use :cl :serapeum)
   (:export ))
 (in-package :infer-type)
 
 (defclass type-env ()
   ((%typedefs :initform (make-hash-table)
               :initarg :typedefs
               :reader typedefs)
    (%typebindings :initform (make-hash-table)
                   :initarg :type-bindings
                   :reader typebindings)
    (%values :initform (make-hash-table)
             :reader values-)))
 
 (defparameter *type-env* (make-instance 'type-env))
 
 (defmacro with-types ((&rest types) (&rest defs) &body body)
   `(let ((*type-env* (make-instance 'type-env
                                     :typedefs
                                     (alexandria:alist-hash-table ',(loop for (type def) in types
                                                                       collect (cons type def)))
                                     :type-bindings
                                     (alexandria:alist-hash-table ',defs))))
      ,@body))
 
 (defun lookup-type (type)
   (gethash type (typedefs *type-env*)))
 
 (defun get-function-type (expr)
   (gethash (car expr)
            (typebindings *type-env*)))
 
 (defun is-type-variable (tyvar)
   (and (symbolp tyvar)
        (char= (elt (symbol-name tyvar)
                    0)
               #\?)))
 
 (defun is-bound-type-variable (tyvar)
   (nth-value 1 (gethash tyvar (typebindings *type-env*))))
 
 (defun lookup-type-variable (tyvar)
   (gethash tyvar (typebindings *type-env*)))
 
 (defun infer-simple-type (expr)
   (loop for k being the hash-keys of (typebindings *type-env*)
      using (hash-value v)
      when (subtypep (type-of expr) v) do
        (return k)))
 
 (defun infer-complex-type (expr)
   (destructuring-bind (ret-type arg-types) (get-function-type expr)
     ))
 
 (defun infer-type (expr)
   (if (is-simple-expression expr)
       (infer-simple-type expr)
       (infer-complex-type expr)))
 
 (defun bind-type-variable (expr tyvar)
   (setf (gethash tyvar (typebindings *type-env*))
         (infer-type expr)))
 
 (defun check-type- (expr type)
   (if (is-type-variable type)
       (if (is-bound-type-variable type)
           (check-type- expr
                        (lookup-type-variable type))
           (bind-type-variable expr type))
       (if (is-simple-expression expr)
           (check-simple-type expr type)
           (check-complex-type expr type))))
 
 (defun is-simple-expression (expr)
   (or (not (listp expr))
       (eql (car expr)
            'quote)))
 
 (defun check-simple-type (expr type)
   (values (subtypep (type-of expr)
                     (lookup-type type))
           type))
 
 (defun check-complex-type (expr type)
   (destructuring-bind (return-type arg-types) (get-function-type expr)
     (values (and (lookup-type return-type)
                  (subtypep (lookup-type return-type)
                            (lookup-type type))
                  (= (1- (length expr))
                     (length arg-types))
                  (every (lambda (arg-expr arg-type)
                           (and (lookup-type arg-type)
                                (check-type- arg-expr arg-type)))
                         (cdr expr)
                         arg-types))
             return-type)))
 
 
 (defun foo (a b)
   (check-type a number)
   (check-type b number)
   (+ a b))
 
 #+null
 (defmacro with-implicit-conversions ((&rest conversions) &body body)
   `(let ((num-coercions 0)
          (coercion-limit 10))
      (handler-bind ((type-error (lambda (c)
                                   (incf num-coercions)
                                   (when (< num-coercions
                                            coercion-limit)
                                     (let ((datum (type-error-datum c))
                                           (expected-type (type-error-expected-type c)))
                                       (store-value
                                        (cond ,@(loop for (type handler) in conversions
                                                   collect `((subtypep ',type expected-type)
                                                             (,handler datum))))))))))
        ,@body)))