scribble-enhanced/graph-lib/lib/low/stx.rkt
2016-03-02 20:21:36 +01:00

407 lines
14 KiB
Racket

#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules
(provide stx-list
stx-e
stx-pair
syntax-cons-property
stx-map-nested
identifier-length
identifier->string
(rename-out [identifier->string identifier→string])
;stx-map-nested
stx-car
stx-cdr
stx-null?
stx-pair?
stx-cons
Stx-List?
Syntax-Pairs-of
stx-drop-last
stx-foldl
stx-assoc
cdr-stx-assoc
check-duplicate-identifiers
nameof
(all-from-out syntax/stx))
(require "typed-untyped.rkt")
(require-typed/untyped "sequence.rkt")
(require syntax/stx)
;; match-expanders:
;; stx-list
;; stx-e
;; stx-pair
(begin
(define-match-expander stx-list
(lambda (stx)
(syntax-case stx ()
[(_ pat ...)
#'(? syntax?
(app syntax->list (list pat ...)))])))
(module+ test
(require typed/rackunit)
(check-equal? (match #'(1 2 3)
[(stx-list a b c) (list (syntax-e c)
(syntax-e b)
(syntax-e a))])
'(3 2 1))
(check-equal? (match #'(1 2 3)
[(stx-list a ...) (map (inst syntax-e Positive-Byte) a)])
'(1 2 3))
#;(check-equal? (match #`(1 . (2 3))
[(stx-list a b c) (list (syntax-e c)
(syntax-e b)
(syntax-e a))])
'(3 2 1)))
;; stx-e
(define-match-expander stx-e
(lambda (stx)
(syntax-case stx ()
[(_ pat)
#'(? syntax?
(app syntax-e pat))])))
(module+ test
(require typed/rackunit)
(check-equal? (match #'x [(stx-e s) s]) 'x)
(check-equal? (match #'(x . y) [(stx-e (cons a b)) (cons (syntax-e b)
(syntax-e a))])
'(y . x)))
(define-match-expander stx-pair
(lambda (stx)
(syntax-case stx ()
[(_ pat-car pat-cdr)
#'(? syntax?
(app syntax-e (cons pat-car pat-cdr)))])))
(module+ test
(require typed/rackunit)
(check-equal? (match #'(x . y) [(stx-pair a b) (cons (syntax-e b)
(syntax-e a))])
'(y . x))
(check-equal? (match #'(x y z) [(stx-pair a b) (cons (map syntax->datum b)
(syntax->datum a))])
'((y z) . x))))
;; utilities:
;; syntax-cons-property
;; identifier-length
;; identifier->string
;; stx-map-nested
(begin
(: syntax-cons-property ( (A) ( (Syntaxof A) Symbol Any (Syntaxof A))))
(define (syntax-cons-property stx key v)
(let ([orig (syntax-property stx key)])
(syntax-property stx key (cons v (or orig '())))))
(: identifier-length ( Identifier Index))
(define (identifier-length id) (string-length (identifier->string id)))
(: identifier->string ( Identifier String))
(define (identifier->string id) (symbol->string (syntax-e id)))
(: stx-map-nested ( (A B) ( ( A B)
(Syntaxof (Listof (Syntaxof (Listof A))))
(Listof (Listof B)))))
(define (stx-map-nested f stx)
(map (λ ([x : (Syntaxof (Listof A))])
(map f (syntax-e x)))
(syntax-e stx))))
;; accessors:
;; stx-car
;; stx-cdr
;; stx-null?
;; stx-pair?
(begin
#|
(require/typed syntax/stx
[stx-car (∀ (A B) (→ (Syntaxof (Pairof A B)) A))]
[stx-cdr (∀ (A B) (→ (Syntaxof (Pairof A B)) B))])
|#
(: stx-car ( (A B)
(case→ ( (Syntaxof (Pairof A B)) A)
;; TODO: Not typesafe!
( (U (Syntaxof (Listof A)) (Listof A)) A))))
(define (stx-car p) (car (if (syntax? p) (syntax-e p) p)))
(: stx-cdr ( (A B)
(case→ ( (Syntaxof (Pairof A B))
B)
;; TODO: Not typesafe!
( (U (Syntaxof (Listof A)) (Listof A))
(Listof A)))))
(define (stx-cdr p) (cdr (if (syntax? p) (syntax-e p) p)))
(: stx-null? ( Any Boolean : (U (Syntaxof Null) Null)))
(define (stx-null? v)
(if-typed
((make-predicate (U (Syntaxof Null) Null)) v)
(or (null? v) (and (syntax? v) (null? (syntax-e v))))))
(module+ test
(check-equal? (stx-null? #f) #f)
(check-equal? (stx-null? 'a) #f)
(check-equal? (stx-null? '()) #t)
(check-equal? (stx-null? #'()) #t)
(check-equal? (stx-null? #''()) #f)
(check-equal? (stx-null? #'a) #f))
(: stx-pair? ( Any Boolean : (U (Pairof Any Any)
(Syntaxof (Pairof Any Any)))))
(define (stx-pair? v)
(if-typed
((make-predicate (U (Pairof Any Any)
(Syntaxof (Pairof Any Any))))
v)
(or (pair? v) (and (syntax? v) (pair? (syntax-e v)))))))
;; constructors:
;; stx-cons
(begin
(module m-stx-cons-untyped racket
(provide stx-cons list->stx list*->stx)
(define (stx-cons a b) #`(#,a . #,b))
(define (list->stx l) #`#,l)
(define (list*->stx l*) #`#,l*))
(if-typed
(module m-stx-cons-typed typed/racket
(provide stx-cons list->stx list*->stx)
(require (only-in typed/racket/unsafe unsafe-require/typed))
(unsafe-require/typed
(submod ".." m-stx-cons-untyped)
[stx-cons ( (A B)
( (Syntaxof A)
(Syntaxof B)
(Syntaxof (Pairof (Syntaxof A) (Syntaxof B)))))]
[list->stx ( (A)
( (Listof (Syntaxof A))
(Syntaxof (Listof (Syntaxof A)))))]
[list*->stx ( (A B)
( (Rec R (U B (Pairof (Syntaxof A) R)))
(Syntaxof (Rec R (U B (Pairof (Syntaxof A) R))))))]))
(module m-stx-cons-typed racket
(provide stx-cons list->stx list*->stx)
(require (submod ".." m-stx-cons-untyped))))
(require 'm-stx-cons-typed)
(module+ test
(require ;(submod "..")
typed/rackunit)
(check-equal? (syntax->datum
(ann (stx-cons #'a #'(b c))
(Syntaxof (Pairof (Syntaxof 'a)
(Syntaxof (List (Syntaxof 'b)
(Syntaxof 'c)))))))
'(a b c))
(check-equal? (syntax->datum
(ann (stx-cons #'1 (ann #'2 (Syntaxof 2)))
(Syntaxof (Pairof (Syntaxof 1)
(Syntaxof 2)))))
'(1 . 2))))
;; stx-drop-last
(begin
(: drop-last ( (A) ( (Listof A) (Listof A))))
(define (drop-last l)
(if (and (pair? l) (pair? (cdr l)))
(cons (car l) (drop-last (cdr l)))
'()))
(define-type (Stx-List? A)
(U Null
(Pairof A (Stx-List? A))
(Syntaxof Null)
(Syntaxof (Pairof A (Stx-List? A)))))
(define-type (Syntax-Pairs-of A)
(U (Syntaxof Null)
(Syntaxof (Pairof A (Syntax-Pairs-of A)))))
(module+ test
(require-typed/untyped "typed-rackunit.rkt")
(check-ann #'() (Stx-List? (Syntaxof Number)))
(check-ann #'(1) (Stx-List? (Syntaxof Number)))
(check-ann #'(1 2 3) (Stx-List? (Syntaxof Number)))
(check-ann #'(1 2 . ()) (Stx-List? (Syntaxof Number)))
(check-ann #'(1 . (2 . (3 . ()))) (Stx-List? (Syntaxof Number)))
(check-ann #'(1 . (2 3 . ())) (Stx-List? (Syntaxof Number)))
(check-ann #'(1 2 . (3 4 . (5))) (Stx-List? (Syntaxof Number))))
(: stx->list ( (A) ( (Stx-List? (Syntaxof A)) (Listof (Syntaxof A)))))
(define (stx->list l)
(cond [(null? l)
'()]
[(pair? l)
(cons (car l) (stx->list (cdr l)))]
[else
(stx->list (syntax-e l))]))
(: stx-drop-last
( (A) ( (Stx-List? (Syntaxof A)) (Syntaxof (Listof (Syntaxof A))))))
(define (stx-drop-last l)
(list->stx (drop-last (stx->list l))))
#|
#;(cond [(null? l)
#'()]
[(pair? l)
(cond [(null? (cdr l))
#'()]
[(pair? (cdr l))
]
[else
(let* ([res (stx-drop-last (cdr l))]
[e (syntax-e res)])
(if (null? e)
(stx-cons (car l) #'())
(stx-cons (car l) res)))]
[else
(stx-drop-last (syntax-e l))])
#;(if (if-typed ((make-predicate (Syntaxof Any)) l) (syntax? l))
(stx-drop-last (syntax-e l))
(if (null? l)
#'()
(stx-cons (car l)
(stx-drop-last (cdr l)))))))
|#)
;; stx-foldl
(begin
(: stx-foldl
( (E F G Acc)
(case→ ( ( E Acc Acc)
Acc
(U (Syntaxof (Listof E)) (Listof E))
Acc)
( ( E F Acc Acc)
Acc
(U (Syntaxof (Listof E)) (Listof E))
(U (Syntaxof (Listof F)) (Listof F))
Acc)
( ( E F G Acc Acc)
Acc
(U (Syntaxof (Listof E)) (Listof E))
(U (Syntaxof (Listof F)) (Listof F))
(U (Syntaxof (Listof G)) (Listof G))
Acc))))
(define stx-foldl
(case-lambda
[(f acc l)
(if (stx-null? l)
acc
(stx-foldl f (f (stx-car l) acc) (stx-cdr l)))]
[(f acc l l2)
(if (or (stx-null? l) (stx-null? l2))
acc
(stx-foldl f
(f (stx-car l) (stx-car l2) acc)
(stx-cdr l)
(stx-cdr l2)))]
[(f acc l l2 l3)
(if (or (stx-null? l) (stx-null? l2) (stx-null? l3))
acc
(stx-foldl f
(f (stx-car l) (stx-car l2) (stx-car l3) acc)
(stx-cdr l)
(stx-cdr l2)
(stx-cdr l3)))])))
;; stx-assoc
;; cdr-stx-assoc
(begin
(: stx-assoc ( (T) (case→
( Identifier
(U (Syntaxof (Listof (Syntaxof (Pairof Identifier
T))))
(Listof (Syntaxof (Pairof Identifier T))))
(U (Syntaxof (Pairof Identifier T)) #f))
( Identifier
(Listof (Pairof Identifier T))
(U (Pairof Identifier T) #f)))))
(define (stx-assoc id alist)
(let* ([e-alist (if (syntax? alist)
(syntax->list alist)
alist)]
[e-e-alist (cond
[(null? e-alist) '()]
[(syntax? (car e-alist))
(map (λ ([x : (Syntaxof (Pairof Identifier T))])
(cons (stx-car x) x))
e-alist)]
[else
(map (λ ([x : (Pairof Identifier T)])
(cons (car x) x))
e-alist)])]
[result (assoc id e-e-alist free-identifier=?)])
(if result (cdr result) #f)))
(: cdr-stx-assoc
( (T) (case→ ( Identifier
(U (Syntaxof (Listof (Syntaxof (Pairof Identifier T))))
(Listof (Syntaxof (Pairof Identifier T)))
(Listof (Pairof Identifier T)))
(U T #f)))))
(define (cdr-stx-assoc id alist)
(if (null? alist)
#f
;; The typechecker is not precise enough, and the code below does not
;; work if we factorize it:
;; (if (and (list? alist) (syntax? (car alist))) … …)
(if (list? alist)
(if (syntax? (car alist))
(let ((res (stx-assoc id alist)))
(if res (stx-cdr res) #f))
(let ((res (stx-assoc id alist)))
(if res (cdr res) #f)))
(let ((res (stx-assoc id alist)))
(if res (stx-cdr res) #f))))))
;; check-duplicate-identifiers
(begin
(: check-duplicate-identifiers ( (Syntaxof (Listof (Syntaxof Symbol)))
Boolean))
(define (check-duplicate-identifiers ids)
(if (check-duplicate-identifier (my-in-syntax ids)) #t #f)))
;; nameof
(begin
;; TODO: use the proper way to introduce arrows if possible.
(define-syntax-rule (nameof x) (begin x 'x))
(module+ test
(require typed/rackunit)
(let ((y 3))
(check-equal? (nameof y) 'y))))
#|
(define (raise-multi-syntax-error name message exprs)
(let ([e (exn:fail:syntax "message"
(current-continuation-marks)
(list #'aaa #'bbb))])
((error-display-handler) (exn-message e) e)))
|#)