Last active
April 23, 2018 18:52
-
-
Save lexi-lambda/7c5bd134b62dc7535dde7b7851397338 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#lang racket/base | |
(require (for-syntax (only-in hackett/private/util/stx | |
syntax/loc/props quasisyntax/loc/props) | |
racket/base | |
racket/list | |
threading) | |
syntax/parse/define) | |
(provide expand-expression) | |
(begin-for-syntax | |
(define current-context (make-parameter #f)) | |
(define current-stop-list (make-parameter (list #'begin))) | |
(define current-intdef-ctx (make-parameter #f)) | |
(define (current-expand stx) | |
(syntax-disarm (local-expand (syntax-disarm stx #f) | |
(current-context) | |
(current-stop-list) | |
(current-intdef-ctx)) | |
#f)) | |
(define-syntax-class plain-formals | |
#:description "formals" | |
#:attributes [[id 1]] | |
#:commit | |
[pattern id*:id #:with [id ...] #'[id*]] | |
[pattern (id:id ...)] | |
[pattern (id*:id ...+ id**:id) #:with [id ...] #'[id* ... id**]]) | |
(define-syntax-class lambda-clause | |
#:description #f | |
#:attributes [expansion] | |
#:commit | |
[pattern [formals:plain-formals body ...] | |
#:do [(define intdef-ctx (syntax-local-make-definition-context (current-intdef-ctx))) | |
(syntax-local-bind-syntaxes (attribute formals.id) #f intdef-ctx)] | |
#:with formals* (internal-definition-context-introduce intdef-ctx #'formals) | |
#:with body* (parameterize ([current-intdef-ctx intdef-ctx]) | |
(expand-body (attribute body))) | |
#:attr expansion #'[formals* body*]]) | |
(define (expand-expression stx) | |
(syntax-parse (parameterize ([current-context 'expression]) | |
(current-expand stx)) | |
#:literal-sets [kernel-literals] | |
[({~or quote quote-syntax #%top #%variable-reference} ~! . _) | |
this-syntax] | |
[({~and head {~or #%expression #%plain-app begin begin0 if with-continuation-mark}} ~! form ...) | |
#:with [form* ...] (map expand-expression (attribute form)) | |
(syntax/loc/props this-syntax | |
(head form* ...))] | |
[(head:set! ~! x:id rhs) | |
(quasisyntax/loc/props this-syntax | |
(head x #,(expand-expression #'rhs)))] | |
[(head:#%plain-lambda ~! . clause:lambda-clause) | |
(syntax/loc/props this-syntax | |
(head . clause.expansion))] | |
[(head:case-lambda ~! clause:lambda-clause ...) | |
(syntax/loc/props this-syntax | |
(head clause.expansion ...))] | |
[({~or {~and {~or {~and head:let-values {~bind [rec? #f]}} | |
{~and head:letrec-values {~bind [rec? #t]}}} | |
~! {~bind [stxs? #f] [[x/s 2] '()] [[rhs/s 1] '()]}} | |
{~seq head:letrec-syntaxes+values {~bind [rec? #t] [stxs? #t]} | |
~! ([(x/s:id ...) rhs/s] ...)}} | |
([(x:id ...) rhs] ...) body ...) | |
#:do [(define intdef-ctx (syntax-local-make-definition-context (current-intdef-ctx))) | |
(syntax-local-bind-syntaxes (append* (attribute x)) #f intdef-ctx) | |
(for ([xs/s (in-list (attribute x/s))] | |
[rhs/s (in-list (attribute rhs/s))]) | |
(syntax-local-bind-syntaxes xs/s rhs/s intdef-ctx))] | |
#:with [[x* ...] ...] (internal-definition-context-introduce intdef-ctx #'[[x ...] ...]) | |
#:with [rhs* ...] (if (attribute rec?) | |
(parameterize ([current-intdef-ctx intdef-ctx]) | |
(map expand-expression (attribute rhs))) | |
(map expand-expression (attribute rhs))) | |
#:with body* (parameterize ([current-intdef-ctx intdef-ctx]) | |
(expand-body (attribute body))) | |
(if (attribute stxs?) | |
(~> (syntax/loc this-syntax | |
(letrec-values ([(x* ...) rhs*] ...) body*)) | |
(syntax-track-origin this-syntax #'head)) | |
(syntax/loc/props this-syntax | |
(head ([(x* ...) rhs*] ...) body*)))] | |
[_ | |
this-syntax])) | |
(define (expand-body stxs) | |
(define intdef-ctx (syntax-local-make-definition-context (current-intdef-ctx))) | |
(parameterize ([current-context (list (gensym))] | |
[current-intdef-ctx intdef-ctx]) | |
(define-values [binding-clauses exprs disappeared-uses disappeared-bindings] | |
(let loop ([stxs stxs] | |
[binding-clauses '()] | |
[exprs '()] | |
[disappeared-uses '()] | |
[disappeared-bindings '()]) | |
(if (empty? stxs) | |
(values (reverse binding-clauses) (reverse exprs) disappeared-uses disappeared-bindings) | |
(syntax-parse (current-expand (first stxs)) | |
#:literal-sets [kernel-literals] | |
[(head:begin ~! form ...) | |
(loop | |
(append (map #{syntax-track-origin % this-syntax #'head} (attribute form)) stxs) | |
binding-clauses exprs disappeared-uses disappeared-bindings)] | |
[(head:define-values ~! [x:id ...] rhs) | |
#:with [x* ...] (map syntax-local-identifier-as-binding (attribute x)) | |
#:do [(syntax-local-bind-syntaxes (attribute x*) #f intdef-ctx)] | |
(loop | |
(rest stxs) | |
(cons (syntax-track-origin #'[(x* ...) rhs] this-syntax #'head) binding-clauses) | |
exprs disappeared-uses disappeared-bindings)] | |
[(head:define-syntaxes ~! [x:id ...] rhs) | |
#:with [x* ...] (map syntax-local-identifier-as-binding (attribute x)) | |
#:do [(syntax-local-bind-syntaxes (attribute x*) #'rhs intdef-ctx)] | |
(loop (rest stxs) binding-clauses exprs | |
(cons #'head disappeared-uses) (cons (attribute x*) disappeared-bindings))] | |
[_ | |
(loop (rest stxs) binding-clauses (cons this-syntax exprs) | |
disappeared-uses disappeared-bindings)])))) | |
(define expanded-binding-clauses | |
(for/list ([binding-clause (in-list binding-clauses)]) | |
(syntax-parse binding-clause | |
[[(x ...) rhs] | |
(quasisyntax/loc/props this-syntax | |
[(x ...) #,(expand-expression #'rhs)])]))) | |
(~> #`(letrec-values #,expanded-binding-clauses #,@exprs) | |
(syntax-property 'disappeared-uses disappeared-uses) | |
(syntax-property 'disappeared-bindings disappeared-bindings))))) | |
(define-syntax-parser expand-expression | |
[(_ form) (expand-expression #'form)]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment