Implemented, tested and documented xlist types

This commit is contained in:
Georges Dupéron 2016-09-21 04:30:39 +02:00
parent 2a1c032572
commit cce0f70c69
9 changed files with 771 additions and 38 deletions

View File

@ -6,4 +6,4 @@
xlist
=====
Fancy lists, with bounded or unbounded repetition of elements. Can be used as a type, match pattern or to create instances.
Fancy lists, with bounded or unbounded repetition of elements. Can be used as a type or match pattern.

11
caret-identifier.rkt Normal file
View File

@ -0,0 +1,11 @@
#lang racket/base
(provide ^)
(require (for-syntax racket/base))
(define-syntax ^
(λ (stx)
(raise-syntax-error
'^
"The ^ identifier can only be used in some contexts"
stx)))

6
infinity-identifier.rkt Normal file
View File

@ -0,0 +1,6 @@
#lang racket/base
(provide )
(require (for-syntax racket/base))
(define +inf.0)

View File

@ -1,8 +1,16 @@
#lang info
(define collection "xlist")
(define deps '("base"
"rackunit-lib"))
(define build-deps '("scribble-lib" "racket-doc"))
"rackunit-lib"
"mutable-match-lambda"
"scribble-enhanced"
"multi-id"
"type-expander"
"typed-racket-lib"))
(define build-deps '("scribble-lib"
"racket-doc"
"typed-racket-doc"
"scribble-math"))
(define scribblings '(("scribblings/xlist.scrbl" ())))
(define pkg-desc "Description Here")
(define version "0.0")

229
main.rkt
View File

@ -1,35 +1,204 @@
#lang racket/base
#lang typed/racket/base
(module+ test
(require rackunit))
(require type-expander
multi-id
"caret-identifier.rkt"
"infinity-identifier.rkt"
(for-syntax
(rename-in racket/base
[* mul]
[+ plus]
[compose ]
[... ])
racket/syntax
racket/match
racket/contract
racket/list
racket/function
racket/string
(rename-in syntax/parse
[...+ …+])
syntax/stx
type-expander/expander))
;; Notice
;; To install (from within the package directory):
;; $ raco pkg install
;; To install (once uploaded to pkgs.racket-lang.org):
;; $ raco pkg install <<name>>
;; To uninstall:
;; $ raco pkg remove <<name>>
;; To view documentation:
;; $ raco docs <<name>>
;;
;; For your convenience, we have included a LICENSE.txt file, which links to
;; the GNU Lesser General Public License.
;; If you would prefer to use a different license, replace LICENSE.txt with the
;; desired license.
;;
;; Some users like to add a `private/` directory, place auxiliary files there,
;; and require them in `main.rkt`.
;;
;; See the current version of the racket style guide here:
;; http://docs.racket-lang.org/style/index.html
(provide xlist xList ^ )
;; Code here
(define-syntax stop
(λ (stx) (raise-syntax-error 'stop "This is a private marker" stx)))
(module+ test
;; Tests to be run with raco test
)
(begin-for-syntax
(define number/rx #px"^(.*?)([⁰¹²³⁴⁵⁶⁷⁸⁹]+)$")
(define */rx #px"^(.*?)⃰$")
(define +/rx #px"^(.*?)([⁰¹²³⁴⁵⁶⁷⁸⁹]*)⁺$")
(define -/rx #px"^(.*?)([⁰¹²³⁴⁵⁶⁷⁸⁹]*)⁻([⁰¹²³⁴⁵⁶⁷⁸⁹]*)$")
(define (regexp-match/c rx)
(and/c string? (λ (s) (regexp-match? rx s))))
(define (id/c id)
(and/c identifier? (λ (i) (free-identifier=? i id))))
(module+ main
;; Main entry point, executed when run with the `racket` executable or DrRacket.
)
(define string-superscript-number/c (regexp-match/c number/rx))
(define string-superscript-*/c (regexp-match/c */rx))
(define string-superscript-+/c (regexp-match/c +/rx))
(define string-superscript--/c (regexp-match/c -/rx))
(define string-superscript-any/c
(or/c string-superscript-number/c
string-superscript-*/c
string-superscript-+/c
string-superscript--/c))
(define normal-rest/c
(or/c (list/c (id/c #'^) exact-nonnegative-integer?)
(list/c (id/c #'^) (id/c #'*))
(list/c (id/c #'^) exact-nonnegative-integer? (id/c #'+))
(list/c (id/c #'^)
exact-nonnegative-integer?
(id/c #'-)
(or/c (id/c #') exact-nonnegative-integer?))))
(define normal-string/c (cons/c string?
normal-rest/c))
(define normal-id/c (cons/c (and/c identifier? (not/c (syntax/c '||)))
normal-rest/c))
(define/contract (string-superscripts->number superscripts)
(-> string-superscript-number/c exact-nonnegative-integer?)
(string->number
(string-join
(map (match-lambda ["" "0"] ["¹" "1"] ["²" "2"] ["³" "3"] ["" "4"]
["" "5"] ["" "6"] ["" "7"] ["" "8"] ["" "9"])
(map string (string->list superscripts))))))
(define/contract (string-superscripts->normal superscripts)
(-> string-superscript-any/c
normal-string/c)
(define ->num string-superscripts->number)
(match superscripts
;; Order is important, the regexpes overlap
[(regexp -/rx (list _ base n m))
(list base
#'^
(if (string=? n "") 0 (->num n))
#'-
(if (string=? m "") #' (->num m)))]
[(regexp number/rx (list _ base n)) (list base #'^ (->num n))]
[(regexp */rx (list _ base)) (list base #'^ #'*)]
[(regexp +/rx (list _ base n))
(list base #'^ (if (string=? n "") 1 (->num n)) #'+)]))
(define/contract (id-superscripts->normal id)
(-> identifier? (or/c #f normal-id/c))
(define str (symbol->string (syntax-e id)))
(if (string-superscript-any/c str)
(match (string-superscripts->normal str)
[(cons "" _) #f]
[(cons base rest) (cons (format-id id "~a" base) rest)])
#f))
(define/contract (only-superscripts->normal id)
(-> identifier? (or/c #f normal-rest/c))
(define str (symbol->string (syntax-e id)))
(if (string-superscript-any/c str)
(match (string-superscripts->normal str)
[(cons "" rest) rest]
[_ #f])
#f))
(define-splicing-syntax-class with-superscripts
(pattern (~seq id:id)
#:do [(define normal (id-superscripts->normal #'id))]
#:when normal
#:with (expanded ) normal)
(pattern (~seq base:expr super:id)
#:do [(define normal (only-superscripts->normal #'super))]
#:when normal
#:with (expanded ) (cons #'base normal)))
(define-syntax-class not-stx-list
(pattern {~not (_ )}))
(define-syntax-class base
#:literals (^ + *)
(pattern {~and base {~not {~or ^ + *}}}))
(define-splicing-syntax-class fixed-repeat
(pattern {~seq :base {~literal ^} power:number}
#:with (expanded ) (map (const #'base)
(range (syntax-e #'power))))
(pattern {~literal stop}
#:with (expanded ) #'())
(pattern e:base
#:with (expanded ) #'(e)))
(define-syntax-class repeat-spec
#:literals (* + - )
(pattern (:number))
(pattern ({~optional :number} +))
(pattern ({~optional :number} - {~optional {~or :number}}))
(pattern (*)))
#;(define-splicing-syntax-class xlist-*-element
#:attributes (base)
(pattern :split-superscript-*-id)
(pattern (~seq base :superscript-ish-*)))
#;(define-splicing-syntax-class xlist-+-element
#:attributes (base min)
(pattern :split-superscript-+-id)
(pattern (~seq base :superscript-ish-+)))
(define (xlist-type context)
;; The order of clauses is important, as they otherwise overlap.
(syntax-parser
#:context context
#:literals (^ * + - stop)
[()
#'Null]
[rest:not-stx-list
#'rest]
[(stop . rest) ;; eliminate the private marker
#'(xlist . rest)]
[(s:with-superscripts . rest)
#'(xlist s.expanded . rest)]
[(:base {~optional ^} *)
#'(Listof base)]
[(:base {~optional ^} * . rest)
#:with R (gensym 'R)
#'(Rec R (U (Pairof base R)
(xList . rest)))]
[(:base {~optional ^} + . rest)
#'(xlist base ^ 1 + . rest)]
[(:base ^ power:nat + . rest)
#'(xlist base ^ power stop base * . rest)]
[(:base ^ - . rest)
#'(xlist base ^ 0 - . rest)]
[(:base ^ from:nat - . rest)
#'(xlist base ^ from stop base * . rest)]
[(:base ^ 0 - to:nat . rest)
#`(U . #,(foldl (λ (iteration u*)
(syntax-case u* ()
[[(_ . base…rest) . _]
#`[(xlist base . base…rest) . #,u*]]))
#'[(xlist . rest)]
(range (syntax-e #'to))))]
[(:base ^ from:nat - to:nat . rest)
#:with difference (- (syntax-e #'to) (syntax-e #'from))
(when (< (syntax-e #'difference) 0)
(raise-syntax-error 'xlist
"invalid range: m is larger than n"
#'-))
#`(xlist base ^ from stop base ^ 0 - difference . rest)]
[(:base ^ from:nat - . rest)
;; "-" is not followed by a number, nor by ∞, so default to ∞.
#`(xlist base ^ from - . rest)]
[(e:fixed-repeat . rest)
#'(List* e.expanded (xList . rest))])))
(define-type-expander (xList stx)
((xlist-type stx) (stx-cdr stx)))
(define-multi-id xlist
#:type-expander (λ (stx) ((xlist-type stx) (stx-cdr stx))))

32
scribble-enhanced.rkt Normal file
View File

@ -0,0 +1,32 @@
#lang racket
(require (for-syntax mutable-match-lambda
racket/string
racket/match
racket/function
racket/syntax)
scribble-enhanced/with-manual)
;; Correctly display xyz⃰, xyzⁿ, xyz⁰, xyz¹, … xyz⁹
(begin-for-syntax
(mutable-match-lambda-add-overriding-clause!
mutable-match-element-id-transformer
#:match-lambda
[(? identifier?
whole-id
(app (compose symbol->string syntax-e)
(pregexp
#px"^(.*?)(⃰|⁺|[⁰¹²³⁴⁵⁶⁷⁸⁹]+⁺?|[⁰¹²³⁴⁵⁶⁷⁸⁹]*⁻[⁰¹²³⁴⁵⁶⁷⁸⁹]*)$"
(list whole base power))))
(define/with-syntax base-id (format-id whole-id "~a" base))
(define/with-syntax power-characters
(string-join
(map (match-lambda ["" "*"]
["" "+"]
["" "-"]
;["ⁿ" "n"]
["" "0"] ["¹" "1"] ["²" "2"] ["³" "3"] ["" "4"]
["" "5"] ["" "6"] ["" "7"] ["" "8"] ["" "9"])
(map string (string->list power)))))
#`(elem (list #,@(if (> (string-length base) 0) #'((racket base-id)) #'())
(superscript power-characters)))]))

View File

@ -1,10 +1,198 @@
#lang scribble/manual
@require[@for-label[xlist
racket/base]]
@require[scribble-enhanced/with-manual
xlist/scribble-enhanced
scribble-math
racket/require
@for-label[xlist
(subtract-in typed/racket/base match-string)
(only-in syntax/parse ...+)
match-string]]
@title{xlist}
@author{georges}
@title[#:style (with-html5 manual-doc-style)]{xlist}
@author[@author+email["Georges Dupéron" "georges.duperon@gmail.com"]]
@defmodule[xlist]
Package Description Here
Fancy lists, with bounded or unbounded repetition of elements. Can be used as a
type or match pattern.
To use the type expander, you must first require the
@racketmodname[type-expander] library.
@deftogether[
[@defform*[#:kind "type-expander"
[(xList τᵢ …)
(xList τᵢ … . rest)]]
@defform*[#:kind "type-expander"
#:literals (^ *)
[(xlist τᵢ …)
(xlist τᵢ … . rest)]
#:grammar
[(τᵢ type
repeated-type)
(repeated-type (code:line type ^ repeat)
(code:line type ^ {repeat})
(code:line type {repeat})
(code:line type superscripted-repeat)
(code:line type *)
(code:line type +)
(code:line superscripted-id))
(repeat (code:line number)
(code:line number +)
(code:line +)
(code:line number - number)
(code:line number -)
(code:line number - ∞)
(code:line - number)
(code:line -)
(code:line *))]]]]{
The notation @racket[type ^ _n], where @racket[_n] is a number, indicates that
the given type should be repeated @racket[_n] times within the list. Therefore,
the following two types are equivalent:
@racketblock[
(xList Number ^ 3 Symbol String ^ 2)
(List Number Number Number Symbol String String)]
The notation @racket[type *] indicates that the given type may be repeated zero
or more times. Therefore, the following two types are equivalent:
@racketblock[
(xList Number * Symbol String *)
(Rec R1 (U (Pairof Number R1)
(List* Symbol (Rec R2 (U (Pairof String R2)
Null)))))]
The notation @racket[type ^ _n +] indicates that the given type may be repeated
@racket[_n] or more times. Therefore, the following two types are equivalent:
@racketblock[
(xList Number ^ {2 +} String)
(List* Number Number (Rec R1 (U (Pairof Number R1)
(List String))))]
When the number preceding @racket[+] is omitted, it defaults to @racket[1].
The notation @racket[type ^ _n - _m] indicates that the given type may be
repeated between @racket[_n] (inclusive) and @racket[_m] (inclusive) times.
Therefore, the following two types are equivalent:
@racketblock[
(xList Number ^ {2 - 5} String)
(U (List Number Number String)
(List Number Number Number String)
(List Number Number Number Number String)
(List Number Number Number Number Number String))]
Be aware that the tail of the @racket[xList] following the use of
@racket[type ^ _n - _m] is repeated @${n - m} times, so if the tail itself
contains uses of @racket[-], the resulting macro-expanded type will be huge,
and may easily make Typed/Racket run out of memory, or slow down the type
checking.
If the first bound is omitted, it defaults to @racket[0], and if the second
bound is omited, it defaults to @racket[∞]. This means that @racket[-] on its
own is equivalent to @racket[*], but the latter form is preferred.
The @racket[superscripted-repeat] is a representation of @racket[repeat] using
superscripted unicode characters, without spaces (i.e. the
@racket[superscripted-repeat] is a single identifier):
@itemlist[
@item{Digits are replaced by their unicode superscripted counterparts
@elem[#:style 'tt "⁰¹²³⁴⁵⁶⁷⁸⁹"]}
@item{@racket[+] and @racket[-] are replaced by their unicode superscripted
counterparts, respectively @elem[#:style 'tt "⁺"] and @elem[#:style 'tt "⁻"]}
@item{@racket[*] is replaced by the unicode character ``COMBINING ASTERISK
ABOVE'' @racket[ ⃰] (code point U+20F0)}
@item{@racket[∞] is always omitted, as @racket[_n - ∞] and @racket[- ∞] are
equivalent to @racket[_n -] and @racket[0 -]}]
A @racket[superscripted-id] is a type identifier ending with a sequence of
characters which would otherwise be valid for @racket[superscripted-repeat]. In
other words, if the @racket[type] is an identifier, the type and the
@racket[superscripted-repeat] can be coalesced into a single identifier.
The identifier @racket[String³] is equivalent to the notations
@racket[String ³] (with a space between the identifier and the @racket[ ⃰]) and
@racket[String ^ 3].
Similarly, the identifier @racket[String⃰] is equivalent to the notations
@racket[String ⃰] (with a space between the identifier and the @racket[ ⃰]),
@racket[String ^ *] (using a regular asterisk, i.e. the multiplication function
in Racket) and @racket[String *] (using a regular asterisk, i.e. the
multiplication function in Racket).
The same logic applies to the other cases.}
@defform*[#:kind "match-expander"
#:link-target? #f
#:literals (^ *)
[(xlist patᵢ ...)
(xlist patᵢ ... . rest)]
#:grammar
[(patᵢ pattern-or-spliced
repeated-pattern
spliced-pattern)
(pattern-or-spliced pattern
spliced-pattern)
(spliced-pattern ,@pattern)
(repeated-pattern (code:line pattern-or-spliced ^ repeat)
(code:line pattern-or-spliced ^ {repeat})
(code:line pattern-or-spliced superscripted-repeat)
(code:line pattern-or-spliced *)
(code:line pattern-or-spliced +)
(code:line superscripted-id))
(repeat (code:line number)
(code:line number +)
(code:line +)
(code:line number - number)
(code:line number -)
(code:line number - ∞)
(code:line - number)
(code:line -)
(code:line *)
(code:line ...)
(code:line ..k)
(code:line ____)
(code:line ___k)
(code:line ...+))]]{
This match expander works like the @racket[xList] type expander, but instead
controls the repetition of match patterns. The repeated patterns are not
literally copied, as this would likely cause errors related to duplicate
attributes. Instead, the @racket[repeat] forms control the number of times a
pattern may be bound, like @racket[...] does.
For convenience and compatibility with existing match patterns, the following
equivalences are provided:
@itemlist[
@item{@racket[...] is equivalent to @racket[*]}
@item{@racket[_..k] is equivalent to @racket[_k +]}
@item{@racket[____] is equivalent to @racket[*]}
@item{@racket[___k] is equivalent to @racket[_k +]}
@item{@racket[...+] is equivalent to @racket[+]}]
Additionally, when @RACKET[#,@pattern] appears as one of the @racket[xlist]
elements, the given @racket[pattern] may match any number of elements in the
list. This is implemented in terms of @racket[append] from the
@racketmodname[match-string] library.
The following two match patterns are therefore equivalent:
@racketblock[
(xlist number?³⁻⁵ ,@(list-no-order number? string?) symbol?⁺)
(append (and (list number? ...) (app length (between/c 3 5)))
(list-no-order number? string?)
(list symbol? ..1))]
Applying a repeat indicator on a splice is not supported yet, i.e.
@racket[(xlist ,@(list-no-order number? string?)⁵)] will not work.}
@defidform[^]{This identifier can only be used within xlist forms.}
@defthing[∞]{This identifier is meant to be used within xlist
forms, but is also equal to @racket[+inf.0] as a convenience. In the future,
this package will make it possible for other packages to overload the meaning
of the @racket[^] and @racket[∞] identifiers, so that the value of @racket[∞]
may depend on the packages loaded (for example a symbolic math package may want
to attach a special value to @racket[∞].}

View File

@ -0,0 +1,173 @@
#lang typed/racket
(require xlist
type-expander
typed/rackunit)
;; Should fail (for now)
;(test-begin
; "(xlist 1 2 3 4 5)"
; (ann '() (xlist))
; (ann '(1) (xlist 1¹))
; (ann '(1 2) (xlist 1¹ 2¹))
; (ann '(1 2 3) (xlist 1¹ 2¹ 3¹))
; (ann '(1 2 3 4) (xlist 1¹ 2¹ 3¹ 4¹))
; (ann '(1 2 3 4 5) (xlist 1¹ 2¹ 3¹ 4¹ 5¹))
; (void))
;; Should fail:
; (xlist ^ 1)
; (xlist ^ 1 +)
; (xlist ^ 1 *)
; (xlist +)
; (xlist *)
;(test-begin
; "(xlist 1 *) and (xlist 1 +) with or witout ^"
; (ann '() (xlist 1 *))
; (ann '(1) (xlist 1 *))
; (ann '(1 1) (xlist 1 *))
; (ann '(1 1 1) (xlist 1 *))
;
; ; NOT (ann '() (xlist 1 +))
; (ann '(1) (xlist 1 +))
; (ann '(1 1) (xlist 1 +))
; (ann '(1 1 1) (xlist 1 +))
;
; (ann '() (xlist 1 ^ *))
; (ann '(1) (xlist 1 ^ *))
; (ann '(1 1) (xlist 1 ^ *))
; (ann '(1 1 1) (xlist 1 ^ *))
;
; ; NOT (ann '() (xlist 1 ^ +))
; (ann '(1) (xlist 1 ^ +))
; (ann '(1 1) (xlist 1 ^ +))
; (ann '(1 1 1) (xlist 1 ^ +))
; (void))
(test-begin
"(xlist Number⃰) and (xlist Number⁺) with or without space"
(ann '() (xlist Number⃰))
(ann '(1) (xlist Number⃰))
(ann '(1 1) (xlist Number⃰))
(ann '(1 1 1) (xlist Number⃰))
; NOT (ann '() (xlist Number⁺))
(ann '(1) (xlist Number⁺))
(ann '(1 1) (xlist Number⁺))
(ann '(1 1 1) (xlist Number⁺))
(ann '() (xlist Number ))
(ann '(1) (xlist Number ))
(ann '(1 1) (xlist Number ))
(ann '(1 1 1) (xlist Number ))
; NOT (ann '() (xlist Number ⁺))
(ann '(1) (xlist 1 ))
(ann '(1 1) (xlist 1 ))
(ann '(1 1 1) (xlist 1 ))
(void))
(test-begin
"(xlist Number⃰) and (xlist Number +) something after"
(ann '() (xlist Number⃰ String⃰))
(ann '(1) (xlist Number⃰ String⃰))
(ann '("b") (xlist Number⃰ String⃰))
(ann '(1 "b") (xlist Number⃰ String⃰))
(ann '(1 1 1 "b" "b") (xlist Number⃰ String⃰))
(ann '(1 1 1) (xlist Number⃰ String⃰))
(ann '("b" "b" "b") (xlist Number⃰ String⃰))
; NOT (ann '() (xlist Number⁺ String⁺))
; NOT (ann '(1) (xlist Number⁺ String⁺))
; NOT (ann '("b") (xlist Number⁺ String⁺))
(ann '(1 "b") (xlist Number⁺ String⁺))
(ann '(1 1 "b") (xlist Number⁺ String⁺))
(ann '(1 "b" "b") (xlist Number⁺ String⁺))
(ann '() (xlist Number String ))
(ann '(1) (xlist Number String ))
(ann '("b") (xlist Number String ))
(ann '(1 "b") (xlist Number String ))
(ann '(1 1 1 "b" "b") (xlist Number String ))
(ann '(1 1 1) (xlist Number String ))
(ann '("b" "b" "b") (xlist Number String ))
; NOT (ann '() (xlist Number ⁺ String ⁺))
; NOT (ann '(1) (xlist Number ⁺ String ⁺))
; NOT (ann '("b") (xlist Number ⁺ String ⁺))
(ann '(1 "b") (xlist Number String ))
(ann '(1 1 "b") (xlist Number String ))
(ann '(1 "b" "b") (xlist Number String ))
(void))
(test-begin
"(xlist Numberⁿ⁺) with or without space"
(ann '(1 1 1) (xlist Number⁺))
(ann '(1 1 1) (xlist Number⁰⁺))
(ann '(1 1 1) (xlist Number¹⁺))
(ann '(1 1 1) (xlist Number²⁺))
(ann '(1 1 1) (xlist Number³⁺))
(ann '(1 1 1) (xlist Number ))
(ann '(1 1 1) (xlist Number ⁰⁺))
(ann '(1 1 1) (xlist Number ¹⁺))
(ann '(1 1 1) (xlist Number ²⁺))
(ann '(1 1 1) (xlist Number ³⁺))
(void))
(test-begin
"(xlist Numberⁱ⁻ⁿ) without space"
(ann '() (xlist Number⁻))
(ann '(1 1 1) (xlist Number⁻))
(ann '() (xlist Number⁰⁻))
(ann '(1 1 1) (xlist Number⁰⁻))
(ann '(1 1 1) (xlist Number¹⁻))
(ann '(1 1 1) (xlist Number²⁻))
(ann '(1 1 1) (xlist Number³⁻))
;(ann '(1 1 1) (xlist Number ^ - ∞))
;(ann '(1 1 1) (xlist Number ^ 0 - ∞))
;(ann '(1 1 1) (xlist Number ^ 1 - ∞))
;(ann '(1 1 1) (xlist Number ^ 2 - ∞))
;(ann '(1 1 1) (xlist Number ^ 3 - ∞))
(ann '(1 1 1) (xlist Number⁰⁻⁵))
(ann '(1 1 1) (xlist Number³⁻⁵))
(ann '(1 1 1 1) (xlist Number⁰⁻⁵))
(ann '(1 1 1 1) (xlist Number³⁻⁵))
(ann '(1 1 1 1 1) (xlist Number⁰⁻⁵))
(ann '(1 1 1 1 1) (xlist Number⁰⁻⁵))
(void))
(test-begin
"(xlist Number ⁱ⁻ⁿ) with space"
(ann '() (xlist Number ))
(ann '(1 1 1) (xlist Number ))
(ann '() (xlist Number ⁰⁻))
(ann '(1 1 1) (xlist Number ⁰⁻))
(ann '(1 1 1) (xlist Number ¹⁻))
(ann '(1 1 1) (xlist Number ²⁻))
(ann '(1 1 1) (xlist Number ³⁻))
;(ann '() (xlist Number ^ - ∞))
;(ann '(1 1 1) (xlist Number ^ - ∞))
;(ann '() (xlist Number ^ 0 - ∞))
;(ann '(1 1 1) (xlist Number ^ 0 - ∞))
;(ann '(1 1 1) (xlist Number ^ 1 - ∞))
;(ann '(1 1 1) (xlist Number ^ 2 - ∞))
;(ann '(1 1 1) (xlist Number ^ 3 - ∞))
(ann '(1 1 1) (xlist Number ⁰⁻⁵))
(ann '(1 1 1) (xlist Number ³⁻⁵))
(ann '(1 1 1 1) (xlist Number ⁰⁻⁵))
(ann '(1 1 1 1) (xlist Number ³⁻⁵))
(ann '(1 1 1 1 1) (xlist Number ⁰⁻⁵))
(ann '(1 1 1 1 1) (xlist Number ⁰⁻⁵))
(void))
(test-begin
"(xlist Numberⁿ⁻ String)"
(ann '("b") (xlist Number⁻ String))
(ann '(1 1 1 "b") (xlist Number⁻ String))
(ann '("b") (xlist Number⁰⁻ String))
(ann '(1 1 1 "b") (xlist Number⁰⁻ String))
(ann '(1 1 1 "b") (xlist Number¹⁻ String))
(ann '(1 1 1 "b") (xlist Number²⁻ String))
(void))

146
test/test-type.rkt Normal file
View File

@ -0,0 +1,146 @@
#lang typed/racket
(require xlist
type-expander
typed/rackunit)
(test-begin
"(xlist 1 2 3 4 5)"
(ann '() (xlist))
(ann '(1) (xlist 1))
(ann '(1 2) (xlist 1 2))
(ann '(1 2 3) (xlist 1 2 3))
(ann '(1 2 3 4) (xlist 1 2 3 4))
(ann '(1 2 3 4 5) (xlist 1 2 3 4 5))
(void))
;; Should fail:
; (xlist ^ 1)
; (xlist ^ 1 +)
; (xlist ^ 1 *)
; (xlist +)
; (xlist *)
(test-begin
"(xlist 1 *) and (xlist 1 +) with or witout ^"
(ann '() (xlist 1 *))
(ann '(1) (xlist 1 *))
(ann '(1 1) (xlist 1 *))
(ann '(1 1 1) (xlist 1 *))
; NOT (ann '() (xlist 1 +))
(ann '(1) (xlist 1 +))
(ann '(1 1) (xlist 1 +))
(ann '(1 1 1) (xlist 1 +))
(ann '() (xlist 1 ^ *))
(ann '(1) (xlist 1 ^ *))
(ann '(1 1) (xlist 1 ^ *))
(ann '(1 1 1) (xlist 1 ^ *))
; NOT (ann '() (xlist 1 ^ +))
(ann '(1) (xlist 1 ^ +))
(ann '(1 1) (xlist 1 ^ +))
(ann '(1 1 1) (xlist 1 ^ +))
(void))
(test-begin
"(xlist Number *) and (xlist Number +) with or witout ^"
(ann '() (xlist Number *))
(ann '(1) (xlist Number *))
(ann '(1 1) (xlist Number *))
(ann '(1 1 1) (xlist Number *))
; NOT (ann '() (xlist Number +))
(ann '(1) (xlist Number +))
(ann '(1 1) (xlist Number +))
(ann '(1 1 1) (xlist Number +))
(ann '() (xlist Number ^ *))
(ann '(1) (xlist Number ^ *))
(ann '(1 1) (xlist Number ^ *))
(ann '(1 1 1) (xlist Number ^ *))
; NOT (ann '() (xlist Number ^ +))
(ann '(1) (xlist 1 ^ +))
(ann '(1 1) (xlist 1 ^ +))
(ann '(1 1 1) (xlist 1 ^ +))
(void))
(test-begin
"(xlist Number *) and (xlist Number +) something after"
(ann '() (xlist Number * String *))
(ann '(1) (xlist Number * String *))
(ann '("b") (xlist Number * String *))
(ann '(1 "b") (xlist Number * String *))
(ann '(1 1 1 "b" "b") (xlist Number * String *))
(ann '(1 1 1) (xlist Number * String *))
(ann '("b" "b" "b") (xlist Number * String *))
; NOT (ann '() (xlist Number + String +))
; NOT (ann '(1) (xlist Number + String +))
; NOT (ann '("b") (xlist Number + String +))
(ann '(1 "b") (xlist Number + String +))
(ann '(1 1 "b") (xlist Number + String +))
(ann '(1 "b" "b") (xlist Number + String +))
(ann '() (xlist Number ^ * String ^ *))
(ann '(1) (xlist Number ^ * String ^ *))
(ann '("b") (xlist Number ^ * String ^ *))
(ann '(1 "b") (xlist Number ^ * String ^ *))
(ann '(1 1 1 "b" "b") (xlist Number ^ * String ^ *))
(ann '(1 1 1) (xlist Number ^ * String ^ *))
(ann '("b" "b" "b") (xlist Number ^ * String ^ *))
; NOT (ann '() (xlist Number ^ + String ^ +))
; NOT (ann '(1) (xlist Number ^ + String ^ +))
; NOT (ann '("b") (xlist Number ^ + String ^ +))
(ann '(1 "b") (xlist Number ^ + String ^ +))
(ann '(1 1 "b") (xlist Number ^ + String ^ +))
(ann '(1 "b" "b") (xlist Number ^ + String ^ +))
(void))
(test-begin
"(xlist Number ^ x +)"
(ann '(1 1 1) (xlist Number +))
(ann '(1 1 1) (xlist Number ^ +))
(ann '(1 1 1) (xlist Number ^ 0 +))
(ann '(1 1 1) (xlist Number ^ 1 +))
(ann '(1 1 1) (xlist Number ^ 2 +))
(ann '(1 1 1) (xlist Number ^ 3 +))
(void))
(test-begin
"(xlist Number ^ x - y)"
(ann '() (xlist Number ^ -))
(ann '(1 1 1) (xlist Number ^ -))
(ann '() (xlist Number ^ 0 -))
(ann '(1 1 1) (xlist Number ^ 0 -))
(ann '(1 1 1) (xlist Number ^ 1 -))
(ann '(1 1 1) (xlist Number ^ 2 -))
(ann '(1 1 1) (xlist Number ^ 3 -))
(ann '() (xlist Number ^ - ))
(ann '(1 1 1) (xlist Number ^ - ))
(ann '() (xlist Number ^ 0 - ))
(ann '(1 1 1) (xlist Number ^ 0 - ))
(ann '(1 1 1) (xlist Number ^ 1 - ))
(ann '(1 1 1) (xlist Number ^ 2 - ))
(ann '(1 1 1) (xlist Number ^ 3 - ))
(ann '(1 1 1) (xlist Number ^ 0 - 5))
(ann '(1 1 1) (xlist Number ^ 3 - 5))
(ann '(1 1 1 1) (xlist Number ^ 0 - 5))
(ann '(1 1 1 1) (xlist Number ^ 3 - 5))
(ann '(1 1 1 1 1) (xlist Number ^ 0 - 5))
(ann '(1 1 1 1 1) (xlist Number ^ 3 - 5))
(void))
(test-begin
"(xlist Number ^ x - String)"
(ann '("b") (xlist Number ^ - String))
(ann '(1 1 1 "b") (xlist Number ^ - String))
(ann '("b") (xlist Number ^ 0 - String))
(ann '(1 1 1 "b") (xlist Number ^ 0 - String))
(ann '(1 1 1 "b") (xlist Number ^ 1 - String))
(ann '(1 1 1 "b") (xlist Number ^ 2 - String))
(void))