;;; This generates code for vars defined in an interface. This looks at ;;; annotations and fills in the slots of the var definition. (define (haskell-codegen/interface mods) (codegen/interface (car mods))) (define (codegen/interface mod) (let ((code '())) (dolist (d (module-decls mod)) (when (not (signdecl? d)) (error 'bad-decl)) (dolist (var (signdecl-vars d)) (let ((v (var-ref-var var))) (setf (var-type v) (var-signature v)) (setf (var-toplevel? v) '#t) (let ((a (lookup-annotation v '|Complexity|))) (when (not (eq? a '#f)) (setf (var-complexity v) (car (annotation-value-args a))))) (let ((a (lookup-annotation v '|LispName|))) (when (not (eq? a '#f)) (let ((lisp-entry (generate-lisp-entry v a))) (push lisp-entry code) (when (memq 'codegen (dynamic *printers*)) (pprint* lisp-entry)))))))) `(begin ,@code))) (define (generate-lisp-entry v a) (let ((lisp-name (read-lisp-object (car (annotation-value-args a)))) (type (maybe-expand-io-type (gtype-type (var-type v))))) (setf (var-optimized-entry v) lisp-name) (if (arrow-type? type) (codegen-lisp-fn v (gather-arg-types type)) (codegen-lisp-const v type)))) (define (codegen-lisp-fn var arg-types) (let* ((aux-definition '()) (wrapper? (foreign-fn-needs-wrapper? var arg-types)) (strictness-annotation (lookup-annotation var '|Strictness|)) (strictness (determine-strictness strictness-annotation arg-types)) (temps (gen-temp-names strictness))) (setf (var-strict? var) '#t) (setf (var-arity var) (length strictness)) (setf (var-strictness var) strictness) (when wrapper? (mlet (((code name) (make-wrapper-fn var (var-optimized-entry var) arg-types))) (setf (var-optimized-entry var) name) (setf aux-definition (list code)))) `(begin ,@aux-definition (define ,(fullname var) ,(maybe-make-box-value (codegen-curried-fn (if wrapper? `(function ,(var-optimized-entry var)) `(lambda ,temps (,(var-optimized-entry var) ,@temps))) (var-strictness var)) '#t))))) (define (determine-strictness a args) (if (eq? a '#f) (map (lambda (x) (declare (ignore x)) '#t) (cdr args)) (parse-strictness (car (annotation-value-args a))))) (define (codegen-lisp-const var type) (let ((conversion-fn (output-conversion-fn type))) (setf (var-strict? var) '#f) (setf (var-arity var) 0) (setf (var-strictness var) '()) `(define ,(fullname var) (delay ,(if (eq? conversion-fn '#f) (var-optimized-entry var) `(,@conversion-fn ,(var-optimized-entry var))))))) (define (maybe-expand-io-type ty) (cond ((and (ntycon? ty) (eq? (ntycon-tycon ty) (core-symbol "IO"))) (**ntycon (core-symbol "Arrow") (list (**ntycon (core-symbol "SystemState") '()) (**ntycon (core-symbol "IOResult") (ntycon-args ty))))) ((arrow-type? ty) (**ntycon (core-symbol "Arrow") (list (car (ntycon-args ty)) (maybe-expand-io-type (cadr (ntycon-args ty)))))) (else ty))) (define (gather-arg-types type) (if (arrow-type? type) (let ((a (ntycon-args type))) (cons (car a) (gather-arg-types (cadr a)))) (list type))) (define (input-conversion-fn ty) (if (ntycon? ty) (let ((tycon (ntycon-tycon ty))) (cond ((eq? tycon (core-symbol "String")) (lambda (x) `(haskell-string->string ,x))) ((eq? tycon (core-symbol "List")) ; needs to convert elements (let ((var (gensym "X")) (inner-fn (input-conversion-fn (car (ntycon-args ty))))) (lambda (x) `(haskell-list->list (lambda (,var) ,(if (eq? inner-fn '#f) var (funcall inner-fn var))) ,x)))) ((eq? tycon (core-symbol "Char")) (lambda (x) `(integer->char ,x))) (else '#f))) '#f)) (define (output-conversion-fn ty) (if (ntycon? ty) (let ((tycon (ntycon-tycon ty))) (cond ((eq? tycon (core-symbol "String")) (lambda (x) `(make-haskell-string ,x))) ((eq? tycon (core-symbol "List")) (let ((var (gensym "X")) (inner-fn (output-conversion-fn (car (ntycon-args ty))))) (lambda (x) `(list->haskell-list (lambda (,var) ,(if (eq? inner-fn '#f) var (funcall inner-fn var))) ,x)))) ((eq? tycon (core-symbol "UnitType")) (lambda (x) `(insert-unit-value ,x))) ((eq? tycon (core-symbol "IOResult")) (lambda (x) (let ((c1 (output-conversion-fn (car (ntycon-args ty))))) `(box ,(apply-conversion c1 x))))) (else '#f))) '#f)) (define (apply-conversion fn x) (if (eq? fn '#f) x (funcall fn x))) (define (foreign-fn-needs-wrapper? var args) (if (lookup-annotation var '|NoConversion|) '#f (ffnw-1 args))) (define (ffnw-1 args) (if (null? (cdr args)) (not (eq? (output-conversion-fn (car args)) '#f)) (or (not (eq? (input-conversion-fn (car args)) '#f)) (systemstate? (car args)) (ffnw-1 (cdr args))))) (define (make-wrapper-fn var fn args) (mlet ((new-fn (symbol-append (fullname var) '|/wrapper|)) (avars (gen-temp-names (cdr args))) (ignore-state? (systemstate? (cadr (reverse args)))) ((arg-conversions res-conversion) (collect-conversion-fns avars args))) (values `(define (,new-fn ,@avars) ,@(if ignore-state? `((declare (ignore ,(car (last avars))))) '()) ,@arg-conversions ,(apply-conversion res-conversion `(,fn ,@(if ignore-state? (butlast avars) avars)))) new-fn))) (define (collect-conversion-fns avars args) (if (null? avars) (values '() (output-conversion-fn (car args))) (mlet ((fn (input-conversion-fn (car args))) ((c1 r) (collect-conversion-fns (cdr avars) (cdr args)))) (values (if (eq? fn '#f) c1 `((setf ,(car avars) ,(funcall fn (car avars))) ,@c1)) r)))) (define (arrow-type? x) (and (ntycon? x) (eq? (ntycon-tycon x) (core-symbol "Arrow")))) (define (systemstate? x) (and (ntycon? x) (eq? (ntycon-tycon x) (core-symbol "SystemState")))) (define (gen-temp-names l) (gen-temp-names-1 l '(A B C D E F G H I J K L M N O P))) (define (gen-temp-names-1 l1 l2) (if (null? l1) '() (if (null? l2) (gen-temp-names-1 l1 (list (gensym "T"))) (cons (car l2) (gen-temp-names-1 (cdr l1) (cdr l2))))))