Skip to content

Instantly share code, notes, and snippets.

@lexi-lambda
Last active April 23, 2018 18:52
Show Gist options
  • Save lexi-lambda/7c5bd134b62dc7535dde7b7851397338 to your computer and use it in GitHub Desktop.
Save lexi-lambda/7c5bd134b62dc7535dde7b7851397338 to your computer and use it in GitHub Desktop.
#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