WIP on unhygienic / chain-able version

This commit is contained in:
Georges Dupéron 2017-04-24 22:26:32 +02:00
parent d69bc53905
commit ee26ad8101
12 changed files with 569 additions and 19 deletions

29
dotlambda/chain.rkt Normal file
View File

@ -0,0 +1,29 @@
#lang racket/base
(provide chain-module-begin)
(require (for-syntax racket/base
syntax/parse
debug-scopes/named-scopes/exptime))
(define-syntax continue
(syntax-parser
[(_ whole-ctx lang lang-modbeg . body)
#:with ({~literal #%plain-module-begin} . expanded-body)
(local-expand (datum->syntax #'whole-ctx
`(,#'lang-modbeg . ,#'body)
#'whole-ctx)
'module-begin
'())
(define new-scope (make-module-like-named-scope
(format "nested-lang-~a" (syntax-e #'lang))))
(new-scope #`(begin . expanded-body))]))
(define-syntax chain-module-begin
(syntax-parser
[{~and whole (_ lang . body)}
#:with lang-modbeg (datum->syntax #'lang '#%module-begin #'lang)
#:with whole-ctx (datum->syntax #'whole 'ctx #'whole)
#'(#%plain-module-begin
(require lang)
(continue whole-ctx lang lang-modbeg . body))]))

View File

@ -5,7 +5,8 @@
make-#%top-interaction)
(require typed/racket)
(require (for-syntax debug-scopes))
(require racket/stxparam
(for-syntax racket/string
racket/list
@ -39,14 +40,18 @@
(define-syntax (make-#%module-begin stx)
(syntax-case stx ()
;; -mrt = -make-rename-transformer
[(_ name wrapped-#%module-begin -define-syntax -mrt)
[(_ name wrapped-#%module-begin -define-syntax -mrt -app1 -syntax)
#'(define-syntax (name stx2)
(syntax-case stx2 ()
[(_ . body)
(datum->syntax
stx2
`(,#'wrapped-#%module-begin
. ,(fold-syntax (replace-dots #' #'-define-syntax #'-mrt)
. ,(fold-syntax (replace-dots #'
#'-define-syntax
#'-mrt
#'-app1
#'-syntax)
#'body))
stx2
stx2)]))]))
@ -54,22 +59,27 @@
(define-syntax (make-#%top-interaction stx)
(syntax-case stx ()
;; -mrt = -make-rename-transformer
[(_ name wrapped-#%top-interaction -define-syntax -mrt)
[(_ name wrapped-#%top-interaction -define-syntax -mrt -app1 -syntax)
#'(define-syntax (name stx2)
(syntax-case stx2 ()
[(_ . body)
(datum->syntax
stx2
`(,#'wrapped-#%top-interaction
. ,(fold-syntax (replace-dots #' #'-define-syntax #'-mrt)
. ,(fold-syntax (replace-dots #'
#'-define-syntax
#'-mrt
#'-app1
#'-syntax)
#'body))
stx2
stx2)]))]))
(define-for-syntax (make-λ l args e percent? -define-syntax -mrt)
(define-for-syntax (make-λ l args e percent?
-define-syntax -mrt -app1 -syntax)
(define percent*
(if (and percent? (>= (length args) 1))
`{(,-define-syntax % (,-mrt #',(car args)))}
`{(,-define-syntax % (,-app1 ,-mrt (,-syntax ,(car args))))}
'{}))
;`(letrec ([%0 (,#'λ ,args ,@percent* ,e)]) %0)
(datum->syntax l `(, ,args ,@percent* ,e) l l))
@ -106,7 +116,7 @@
found)
(begin-for-syntax
(define-splicing-syntax-class (elt -define-syntax -mrt)
(define-splicing-syntax-class (elt -define-syntax -mrt -app1 -syntax)
(pattern {~seq {~and l {~datum λ.}} e:expr}
#:with expanded
(let ([args (for/list ([arg (in-range 1 (add1 (find-% #'e)))])
@ -114,7 +124,7 @@
(string->symbol (format "%~a" arg))
#'l
#'l))])
(make-λ #'l args #'e #t -define-syntax -mrt)))
(make-λ #'l args #'e #t -define-syntax -mrt -app1 -syntax)))
(pattern {~seq l:id e:expr}
#:when (regexp-match #px"^λ([^.]+\\.)+$" (identifier→string #'l))
#:with expanded
@ -122,11 +132,12 @@
[args (make-args #'l
m
(+ (syntax-position #'l) 1))])
(make-λ #'l args #'e #f -define-syntax -mrt)))
(make-λ #'l args #'e #f -define-syntax -mrt -app1 -syntax)))
(pattern e
#:with expanded #'e)))
(define-for-syntax ((replace-dots -define-syntax -mrt) stx recurse)
(define-for-syntax ((replace-dots -define-syntax -mrt -app1 -syntax)
stx recurse)
(syntax-parse stx
;; Fast path: no dots or ellipses.
[x:id #:when (regexp-match #px"^[^.…]*$" (identifier→string #'x))
@ -164,7 +175,7 @@
#,(car identifiers))
(quasisyntax/loc stx
(#,(datum->syntax #'here '#%dotted-id stx stx) id ))))]
[{~and whole ({~var || (elt -define-syntax -mrt)}
[{~and whole ({~var || (elt -define-syntax -mrt -app1 -syntax)}
. {~and tail {~not (_ . _)}})}
;; TODO: keep the stx-pairs vs stx-lists structure where possible.
(recurse (datum->syntax #'whole

View File

@ -1,18 +1,42 @@
#lang racket/base
(require dotlambda/implementation
(for-syntax racket/base))
(for-meta -10 racket/base)
(for-meta -9 racket/base)
(for-meta -8 racket/base)
(for-meta -7 racket/base)
(for-meta -6 racket/base)
(for-meta -5 racket/base)
(for-meta -4 racket/base)
(for-meta -3 racket/base)
(for-meta -2 racket/base)
(for-meta -1 racket/base)
(for-meta 0 racket/base)
(for-meta 1 racket/base)
(for-meta 2 racket/base)
(for-meta 3 racket/base)
(for-meta 4 racket/base)
(for-meta 5 racket/base)
(for-meta 6 racket/base)
(for-meta 7 racket/base)
(for-meta 8 racket/base)
(for-meta 9 racket/base)
(for-meta 10 racket/base))
(make-#%module-begin new-#%module-begin
#%module-begin
λ
define-syntax
make-rename-transformer)
make-rename-transformer
#%plain-app
syntax)
(make-#%top-interaction new-#%top-interaction
#%top-interaction
λ
define-syntax
make-rename-transformer)
make-rename-transformer
#%plain-app
syntax)
(provide (except-out (all-from-out racket/base)
#%module-begin

View File

@ -0,0 +1,6 @@
#lang hyper-literate (dotlambda/unhygienic . typed/racket)
@chunk[<*>
(require typed/rackunit)
(define l λ.(list % 1))
(check-equal? ((ann l ( Any (Listof Any))) "b")
'("b" 1))]

View File

@ -0,0 +1,5 @@
#lang dotlambda/unhygienic typed/racket
(require typed/rackunit)
(define l λ.(list % 1))
(check-equal? ((ann l ( Any (Listof Any))) "b")
'("b" 1))

View File

@ -0,0 +1,4 @@
#lang typed/dotlambda
(require (for-syntax racket/base))
(begin-for-syntax
λ.(+ % 1))

132
dotlambda/type-expander.rkt Normal file
View File

@ -0,0 +1,132 @@
#lang racket/base
(require dotlambda/implementation
(for-meta -10 (only-meta-in 0 type-expander/lang))
(for-meta -9 (only-meta-in 0 type-expander/lang))
(for-meta -8 (only-meta-in 0 type-expander/lang))
(for-meta -7 (only-meta-in 0 type-expander/lang))
(for-meta -6 (only-meta-in 0 type-expander/lang))
(for-meta -5 (only-meta-in 0 type-expander/lang))
(for-meta -4 (only-meta-in 0 type-expander/lang))
(for-meta -3 (only-meta-in 0 type-expander/lang))
(for-meta -2 (only-meta-in 0 type-expander/lang))
(for-meta -1 (only-meta-in 0 type-expander/lang))
(for-meta 0 (only-meta-in 0 type-expander/lang))
(for-meta 1 (only-meta-in 0 type-expander/lang))
(for-meta 2 (only-meta-in 0 type-expander/lang))
(for-meta 3 (only-meta-in 0 type-expander/lang))
(for-meta 4 (only-meta-in 0 type-expander/lang))
(for-meta 5 (only-meta-in 0 type-expander/lang))
(for-meta 6 (only-meta-in 0 type-expander/lang))
(for-meta 7 (only-meta-in 0 type-expander/lang))
(for-meta 8 (only-meta-in 0 type-expander/lang))
(for-meta 9 (only-meta-in 0 type-expander/lang))
(for-meta 10 (only-meta-in 0 type-expander/lang))
(only-in (for-meta -10 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -9 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -8 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -7 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -6 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -5 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -4 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -3 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -2 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -1 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 0 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 1 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 2 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 3 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 4 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 5 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 6 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 7 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 8 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 9 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 10 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax]))
(make-#%module-begin new-#%module-begin
#%module-begin
λ
define-syntax
-make-rename-transformer
-#%plain-app
-syntax)
(make-#%top-interaction new-#%top-interaction
#%top-interaction
λ
define-syntax
-make-rename-transformer
-#%plain-app
-syntax)
(provide (except-out (all-from-out type-expander/lang)
#%module-begin
#%top-interaction)
(except-out (all-from-out dotlambda/implementation)
make-#%module-begin
make-#%top-interaction)
(rename-out [new-#%module-begin #%module-begin]
[new-#%top-interaction #%top-interaction]))

View File

@ -0,0 +1,2 @@
(module reader syntax/module-reader
dotlambda/unhygienic)

View File

@ -0,0 +1,222 @@
#lang racket
(provide #%dotted-id
#%dot-separator
new-#%module-begin
make-#%top-interaction)
(require typed/racket
"chain.rkt")
(require (for-syntax debug-scopes))
(require racket/stxparam
(for-syntax racket/string
racket/list
syntax/parse
racket/syntax
syntax/strip-context
racket/struct
racket/function
syntax/srcloc
"private/fold.rkt"
(only-in racket/base [... ])))
(define-for-syntax identifier→string (compose symbol->string syntax-e))
(define-syntax (#%dot-separator stx)
(raise-syntax-error '#%dot-separator
"Can only be used in special contexts"
stx))
(define-syntax (~> stx)
(syntax-case stx ()
[(_ v) #'v]
[(_ v f . f*) #'(~> (f v) . f*)]))
(define-syntax-parameter #%dotted-id
(syntax-parser
#:literals (#%dot-separator)
[(_ {~seq #%dot-separator e} ) #'(λ (v) (~> v e ))]
[(_ e₀ {~seq #%dot-separator e} ) #'(~> e₀ e )]))
(define-syntax (new-#%module-begin stx)
(syntax-parse stx
[(_ {~or lang:id (lang:id . chain₊)} . body)
(datum->syntax
stx
`(,#'chain-module-begin ,#'lang ,@(if (attribute chain₊) `(,#'chain₊) '())
. ,(fold-syntax replace-dots #'body))
stx
stx)]))
(define-syntax (make-#%top-interaction stx)
(syntax-case stx ()
[(_ name wrapped-#%top-interaction)
#'(define-syntax (name stx2)
(syntax-case stx2 ()
[(_ . body)
(datum->syntax
stx2
`(,#'wrapped-#%top-interaction
. ,(fold-syntax replace-dots
#'body))
stx2
stx2)]))]))
(define-for-syntax (make-λ l args e percent?)
(define %-loc
(build-source-location-list
(update-source-location l
#:position (let ([p (syntax-position l)])
(and p (+ p 1)))
#:column (let ([c (syntax-column l)])
(and c (+ c 1)))
#:span 1)))
(define percent*
(if (and percent? (>= (length args) 1))
#`{(define-syntax #,(datum->syntax l '% %-loc)
(#%plain-app make-rename-transformer #'#,(car args)))}
#'{}))
;`(letrec ([%0 (,#'λ ,args ,@percent* ,e)]) %0)
(define
(datum->syntax #'here 'λ
(build-source-location-list
(update-source-location l #:span 1))))
(datum->syntax l #`(#, #,args #,@percent* #,e) l l))
(define-for-syntax (make-args l str* pos)
(if (empty? str*)
'()
(let ()
(define str (car str*))
(define len (string-length str))
(cons (datum->syntax l
(string->symbol str)
(update-source-location l
#:position pos
#:span len)
l)
(make-args l (cdr str*) (+ pos 1 len))))))
(define-for-syntax (find-% stx)
(define found 0)
(define (found! n) (set! found (max found n)))
(fold-syntax (λ (e recurse)
(if (and (identifier? e)
(regexp-match #px"^%[1-9][0-9]*$"
(identifier→string e)))
(found! (string->number
(cadr (regexp-match #px"^%([1-9][0-9]*)$"
(identifier→string e)))))
(if (and (identifier? e)
(string=? (identifier→string e) "%"))
(found! 1)
(recurse e))))
stx)
found)
(begin-for-syntax
(define-splicing-syntax-class elt
(pattern {~seq {~and l {~datum λ.}} e:expr}
#:with expanded
(let ([args (for/list ([arg (in-range 1 (add1 (find-% #'e)))])
(datum->syntax #'l
(string->symbol (format "%~a" arg))
#'l
#'l))])
(make-λ #'l args #'e #t)))
(pattern {~seq l:id e:expr}
#:when (regexp-match #px"^λ([^.]+\\.)+$" (identifier→string #'l))
#:with expanded
(let* ([m (regexp-match* #px"[^.]+" (identifier→string #'l) 1)]
[args (make-args #'l
m
(+ (syntax-position #'l) 1))])
(make-λ #'l args #'e #f)))
(pattern e
#:with expanded #'e)))
(define-for-syntax (replace-dots stx recurse)
(syntax-parse stx
;; Fast path: no dots or ellipses.
[x:id #:when (regexp-match #px"^[^.…]*$" (identifier→string #'x))
#'x]
;; Protected identifiers, which are not altered.
[x:id #:when (regexp-match #px"^(\\.*|…|\\.\\.\\.?[+*]|…[+*]|::\\.\\.\\.)$"
(identifier→string #'x))
#'x]
;; A trailing dot is dropped and escapes the preceding identifier.
[x:id #:when (regexp-match #px"\\.$" (identifier→string #'x))
(let* ([str (identifier→string #'x)]
[unescaped (substring str 0 (sub1 (string-length str)))])
(datum->syntax stx (string->symbol unescaped) stx stx))]
[x:id #:when (regexp-match #px"[.…]"
(identifier→string #'x))
(let* ([str (symbol->string (syntax-e #'x))]
[leading-dot? (regexp-match #px"^\\." str)]
[components* (regexp-match* #px"([^.…]|\\.\\.+)+|…"
str
#:gap-select? #t)]
[components (if leading-dot?
(drop-right components* 1)
(cdr (drop-right components* 1)))]
[unescaped (map (λ (m)
(regexp-replace* #px"\\.(\\.+)" m "\\1"))
components)]
[identifiers ((to-ids stx) components
unescaped
0
leading-dot?)]
[trailing-dot? (regexp-match #px"\\.$" str)])
(define/with-syntax (id ) identifiers)
(if (= (length identifiers) 1)
(quasisyntax/loc stx
#,(car identifiers))
(quasisyntax/loc stx
(#,(datum->syntax #'here '#%dotted-id stx stx) id ))))]
[{~and whole (:elt . {~and tail {~not (_ . _)}})}
;; TODO: keep the stx-pairs vs stx-lists structure where possible.
(recurse (datum->syntax #'whole
(syntax-e #'(expanded . tail))
#'whole
#'whole))]
[_ (recurse stx)]))
(define-for-syntax (to-ids stx)
(define (process component* unescaped* len-before dot?)
(if (empty? component*)
'()
(let ()
(define component (car component*))
(define unescaped (car unescaped*))
(define len (string-length component))
(define len-after (+ len-before len))
(define pos (+ (syntax-position stx) len-before))
(define loc (update-source-location stx #:position pos #:span len))
(define id
(datum->syntax stx
(if dot?
'#%dot-separator
(string->symbol unescaped))
loc
stx))
(define id-p
(if dot? (syntax-property id 'dotted-original-chars unescaped) id))
(cons id-p
(process (cdr component*)
(cdr unescaped*)
len-after
(not dot?))))))
process)
(define-for-syntax (map-fold f init . l*)
(car
(apply foldl
(λ all-args
(define vs+acc (last all-args))
(define args (drop-right all-args 1))
(define new-v+new-acc (apply f (append args (list (cdr vs+acc)))))
(cons (cons (car new-v+new-acc)
(car vs+acc))
(cdr new-v+new-acc)))
(cons '() init)
l*)))

6
dotlambda/unhygienic.rkt Normal file
View File

@ -0,0 +1,6 @@
#lang racket
(require dotlambda/unhygienic-implementation)
(provide (rename-out [new-#%module-begin #%module-begin]
#;[new-#%top-interaction #%top-interaction]))

View File

@ -0,0 +1,2 @@
(module reader syntax/module-reader
dotlambda/unhygienic)

View File

@ -1,19 +1,126 @@
#lang racket/base
(require dotlambda/implementation
typed/racket/base
(for-syntax racket/base))
(for-meta -10 typed/racket/base)
(for-meta -9 typed/racket/base)
(for-meta -8 typed/racket/base)
(for-meta -7 typed/racket/base)
(for-meta -6 typed/racket/base)
(for-meta -5 typed/racket/base)
(for-meta -4 typed/racket/base)
(for-meta -3 typed/racket/base)
(for-meta -2 typed/racket/base)
(for-meta -1 typed/racket/base)
(for-meta 0 typed/racket/base)
(for-meta 1 typed/racket/base)
(for-meta 2 typed/racket/base)
(for-meta 3 typed/racket/base)
(for-meta 4 typed/racket/base)
(for-meta 5 typed/racket/base)
(for-meta 6 typed/racket/base)
(for-meta 7 typed/racket/base)
(for-meta 8 typed/racket/base)
(for-meta 9 typed/racket/base)
(for-meta 10 typed/racket/base)
(only-in (for-meta -10 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -9 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -8 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -7 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -6 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -5 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -4 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -3 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -2 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta -1 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 0 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 1 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 2 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 3 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 4 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 5 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 6 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 7 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 8 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 9 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax])
(only-in (for-meta 10 racket/base)
[make-rename-transformer -make-rename-transformer]
[#%plain-app -#%plain-app]
[syntax -syntax]))
(make-#%module-begin new-#%module-begin
#%module-begin
λ
define-syntax
make-rename-transformer)
-make-rename-transformer
-#%plain-app
-syntax)
(make-#%top-interaction new-#%top-interaction
#%top-interaction
λ
define-syntax
make-rename-transformer)
-make-rename-transformer
-#%plain-app
-syntax)
(provide (except-out (all-from-out typed/racket/base)
#%module-begin