commit c89285f39b2bcfe41f61b3317504e303051a6909
parent 41f7dc0f508ff0b25df3e3d6b8444933f14b8c35
Author: Georges Dupéron <georges.duperon@gmail.com>
Date: Thu, 4 May 2017 23:02:13 +0200
Added contract→type
Diffstat:
3 files changed, 85 insertions(+), 0 deletions(-)
diff --git a/contracts-to-types.rkt b/contracts-to-types.rkt
@@ -0,0 +1,44 @@
+#lang type-expander
+
+(provide :contract→type
+ (rename-out [c→t contract→type]
+ [c→t contract->type]
+ [:contract→type :contract->type]))
+(require racket/contract/base
+ (for-syntax syntax/parse
+ type-expander/expander))
+
+(define-type-expander c→t
+ (syntax-parser
+ [(_ ({~literal or/c} alt ...)) #'(U (c→t alt) ...)]
+ [(_ ({~literal and/c} alt ...)) #'(∩ (c→t alt) ...)]
+ [(_ ({~literal listof} c)) #'(Listof (c→t c))]
+ [(_ ({~literal list/c} c ...)) #'(List (c→t c) ...)]
+ [(_ ({~literal *list/c} prefix suffix ...)) #'(Rec R (U (Pairof prefix R)
+ (List suffix ...)))]
+ [(_ ({~literal vectorof} c)) #'(Vectorof (c→t c))]
+ [(_ ({~literal vector/c} c ...)) #'(Vector (c→t c) ...)]
+ [(_ ({~literal cons/c} a d)) #'(Pairof (c→t a) (c→t d))]
+ [(_ {~literal integer?}) #'Integer]
+ [(_ {~literal string?}) #'String]
+ [(_ {~literal symbol?}) #'Symbol]
+ [(_ {~literal exact-nonnegative-integer?}) #'Exact-Nonnegative-Integer]
+ [(_ {~literal exact-positive-integer?}) #'Exact-Positive-Integer]
+ [(_ {~and τ ({~literal quote} _)}) #'τ]
+ [(_ {~and τ {~or :number :str :id}}) #''τ]
+ [(_ {~and τ ({~literal quasiquote} _)}) #'τ]
+ [(_ ({~literal unquote} τ)) #'τ]
+ [(_ c) (raise-syntax-error
+ 'contract→type
+ (string-append
+ "I cannot convert this contract to a type automatically."
+ " Please fill in an issue at"
+ " https://github.com/jsmaniac/type-expander/issues if the translation"
+ " can easily be done automatically, or do the translation manually "
+ " otherwise. "
+ (format "~a" (syntax->datum #'c)))
+ #'c)]))
+
+(define-syntax (:contract→type stx)
+ (syntax-case stx ()
+ [(_ c) #`(writeln '#,(expand-type #`(c→t c)))]))
+\ No newline at end of file
diff --git a/scribblings/contracts-to-types.scrbl b/scribblings/contracts-to-types.scrbl
@@ -0,0 +1,37 @@
+#lang scribble/manual
+
+@require[(for-label racket/contract/base)
+ scribble/example]
+@title{Using contract syntax to specify types}
+
+@defmodule[type-expander/contracts-to-types]
+
+@defform*[{(contract→type contract)
+ (contract->type contract)}]{
+
+ This is a simple type expander which translates common contracts to types.
+ Note that it only supports a limited number of contract constructors. The
+ following are supported: @racket[or/c], @racket[and/c] (the translation may
+ produce a type too complex for Typed/Racket to understand properly, though),
+ @racket[listof], @racket[list/c], @racket[*list/c], @racket[vectorof],
+ @racket[vector/c], @racket[cons/c], @racket[integer?], @racket[string?],
+ @racket[symbol?], @racket[exact-nonnegative-integer?],
+ @racket[exact-positive-integer?], @racket['quoted-datum],
+ @racket[`quasiquoted-datum-with-unquoted-types].
+
+ Furthermore, using @racket[,_τ] anywhere outside of a quoted datum will leave
+ the type @racket[_τ] unchaged, allowing the user to manually convert to types
+ only the parts which cannot be converted automatically.}
+
+@defform*[{(:contract→type contract)
+ (:contract->type contract)}]{
+
+ Prints a representation of the contract translated as a type. It is then
+ possible to copy-paste that result into the code.
+
+ @examples[
+ (require type-expander/lang
+ racket/contract/base
+ type-expander/contracts-to-types)
+ (:contract→type (list/c 1 2 "str" (or/c integer? string?)))]
+}
diff --git a/scribblings/type-expander.scrbl b/scribblings/type-expander.scrbl
@@ -842,3 +842,5 @@ arguments to a type expander.
define-struct/exec:]
@include-section{deprecated-colon.scrbl}
+
+@include-section{contracts-to-types.scrbl}
+\ No newline at end of file