4e987026 |
;;; 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))))))
|