Skip to content

refactor name mangling #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hackett-doc/scribble/manual/hackett.rkt
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
(require hackett/private/type-reqprov

(for-label hackett
(only-in (unmangle-types-in #:no-introduce (only-types-in hackett)) =>))
(only-in (unmangle-types-in #:no-introduce #:only hackett) =>))

(for-syntax racket/base
racket/contract
2 changes: 1 addition & 1 deletion hackett-lib/hackett/private/adt.rkt
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@
(except-in hackett/private/base @%app)
(only-in hackett/private/class class-id derive-instance)
(only-in hackett/private/kernel [λ plain-λ])
(only-in (unmangle-types-in #:no-introduce (only-types-in hackett/private/kernel))
(only-in (unmangle-types-in #:no-introduce #:only hackett/private/kernel)
forall [#%app @%app]))

(provide (for-syntax type-constructor-spec data-constructor-spec
2 changes: 1 addition & 1 deletion hackett-lib/hackett/private/class.rkt
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@

(for-syntax hackett/private/infix)
(except-in hackett/private/base @%app)
(only-in (unmangle-types-in #:no-introduce (only-types-in hackett/private/kernel))
(only-in (unmangle-types-in #:no-introduce #:only hackett/private/kernel)
∀ => [#%app @%app]))

(provide (for-syntax class-id)
3 changes: 1 addition & 2 deletions hackett-lib/hackett/private/kernel.rkt
Original file line number Diff line number Diff line change
@@ -54,8 +54,7 @@

(define-syntax-parser #%require/only-types
[(_ require-spec ...)
(type-namespace-introduce
#'(@%require (only-types-in require-spec ...)))])
#'(require (unmangle-types-in #:only require-spec ...))])

(define-syntax-parser λ
[(_ [x:id] e:expr)
80 changes: 80 additions & 0 deletions hackett-lib/hackett/private/mangle/mangle-identifier.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#lang racket/base

(provide make-id-mangler
or/unmangler
prefix/unmangler
no-introduce/unmangler
id-mangler
no-introduce/mangler)

(require racket/match
racket/syntax
"mangle-string.rkt")

;; An IdMangler is an (id-mangler StxIntroducer StringMangler)
(struct id-mangler [introducer string-mangler])

;; An IdUnmangler is a function:
;; Identifier -> [Maybe Identifier]

;; ---

;; A StringMangler is a function:
;; String -> String

;; A StringUnmangler is a function:
;; String -> [Maybe String]

;; A StxIntroducer is a function:
;; Syntax -> Syntax
;; Which adds or removes scopes from the input without
;; changing the datum, source-location, or other properties.

;; ---

;; #:prefix String #:introducer StxIntroducer ->
;; (values IdMangler IdUnmangler)
(define (make-id-mangler #:prefix mangle-prefix #:introducer intro)
(define-values [str-mangler str-unmangler]
(make-string-mangler #:prefix mangle-prefix))
(values (id-mangler intro str-mangler)
(string-unmangler->id-unmangler str-unmangler intro)))

;; IdUnmangler ... -> IdUnmangler
(define ((or/unmangler . id-un*) x)
(for/or ([id-un (in-list id-un*)])
(id-un x)))

;; Symbol IdUnmangler -> IdUnmangler
(define ((prefix/unmangler pre id-un) x)
(define unmangled (id-un x))
(and unmangled
(format-id unmangled "~a~a" pre unmangled
#:source unmangled #:props unmangled)))

;; IdUnmangler -> IdUnmangler
(define ((no-introduce/unmangler id-un) x)
(define unmangled (id-un x))
(and unmangled
(datum->syntax x (syntax-e unmangled) x x)))

;; IdUnmangler -> IdUnmangler
(define (no-introduce/mangler id-mangler*)
(match-define (id-mangler _ string-mangler) id-mangler*)
(id-mangler values string-mangler))

;; ---------------------------------------------------------

;; StringUnmangler StxIntroducer -> IdUnmangler
(define ((string-unmangler->id-unmangler str-unmangle intro) x)
(define name (symbol->string (syntax-e x)))
(cond
[(str-unmangle name)
=>
(λ (unmangled-name)
(intro
(datum->syntax x (string->symbol unmangled-name) x x)))]
[else
#false]))

;; ---------------------------------------------------------
34 changes: 34 additions & 0 deletions hackett-lib/hackett/private/mangle/mangle-import-export.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#lang racket/base

(provide mangle-export
unmangle-import)

(require racket/match
racket/provide-transform
racket/require-transform
threading
"mangle-identifier.rkt")

;; ---------------------------------------------------------

;; Export StringMangler -> Export
(define (mangle-export e id-mangler*)
(match-define (id-mangler intro mangle-str) id-mangler*)
(struct-copy export e
[local-id (intro (export-local-id e))]
[out-sym (~>> (export-out-sym e)
symbol->string
mangle-str
string->symbol)]))

;; Import IdUnmangler -> [Maybe Import]
(define (unmangle-import i id-unmangler)
(match i
[(import local-id src-sym src-mod-path mode req-mode orig-mode orig-stx)
(define unmangled (id-unmangler local-id))
(and unmangled
(import unmangled
src-sym src-mod-path mode req-mode orig-mode orig-stx))]))

;; ---------------------------------------------------------

70 changes: 70 additions & 0 deletions hackett-lib/hackett/private/mangle/mangle-reqprov.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#lang racket/base

(provide make-unmangling-require-transformer
make-mangling-provide-transformer)

(require racket/function
racket/list
racket/provide-transform
racket/require-transform
syntax/parse
(only-in syntax/parse [attribute @])
threading
(for-template racket/base)
"mangle-identifier.rkt"
"mangle-import-export.rkt")

;; ---------------------------------------------------------

;; #:mangle-prefix String
;; #:introducer StxIntroducer
;; ->
;; RequireTransformer
(define (make-unmangling-require-transformer id-unmangler)
(make-require-transformer
(syntax-parser
[(_ {~alt {~optional {~or {~and #:no-introduce no-introduce?}
{~seq #:prefix prefix:id}}}
{~optional {~and #:only only?}}}
...
require-spec ...)
#:do [(define id-unmangler*
(let* ([unm id-unmangler]
[unm (if (or (@ no-introduce?) (@ prefix))
(no-introduce/unmangler unm)
unm)]
[unm (if (@ prefix)
(prefix/unmangler (syntax-e (@ prefix)) unm)
unm)])
unm))

(define-values [imports sources]
(expand-import #'(combine-in require-spec ...)))]

(values (for*/list ([i (in-list imports)]
[i* (in-value (unmangle-import i id-unmangler*))]
#:when (if (@ only?) i* #t))
(or i* i))
sources)])))

;; #:mangle-prefix String
;; #:introducer StxIntroducer
;; ->
;; ProvideTransformer
(define (make-mangling-provide-transformer id-mangler)
(make-provide-transformer
(λ (stx modes)
(syntax-parse stx
[(_ {~optional {~and #:no-introduce no-introduce?}} provide-spec ...)
#:do [(define id-mangler*
(if (@ no-introduce?)
(no-introduce/mangler id-mangler)
id-mangler))

(define exports
(expand-export (syntax/loc this-syntax
(combine-out provide-spec ...))
modes))]

(for/list ([e (in-list exports)])
(mangle-export e id-mangler*))]))))
44 changes: 44 additions & 0 deletions hackett-lib/hackett/private/mangle/mangle-string.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#lang racket/base

(provide make-string-mangler)

(require threading
racket/list)
(module+ test
(require rackunit))

;; A StringMangler is a function:
;; String -> String

;; A StringUnmangler is a function:
;; String -> [Maybe String]

;; #:prefix String -> (values StringMangler StringUnmangler)
(define (make-string-mangler #:prefix mangle-prefix)
(define mangled-regexp
(regexp (string-append "^"
(regexp-quote mangle-prefix)
"(.*)$")))

;; String -> String
(define (mangle-string name)
(string-append mangle-prefix name))

;; String -> [Maybe String]
(define (unmangle-string name)
(and~> (regexp-match mangled-regexp name) second))

(values mangle-string unmangle-string))

;; ---------------------------------------------------------

(module+ test
(define pre "#%hackett-test:")
(define-values [mangle unmangle]
(make-string-mangler #:prefix pre))

(check-equal? (unmangle (mangle "ahotenus")) "ahotenus")
(check-equal? (unmangle (mangle "jatkae")) "jatkae")
(check-equal? (unmangle "ahotenus") #false)
)

4 changes: 2 additions & 2 deletions hackett-lib/hackett/private/prim/op.rkt
Original file line number Diff line number Diff line change
@@ -10,8 +10,8 @@
racket/string))

hackett/private/base
(only-in (unmangle-types-in #:no-introduce (only-types-in hackett/private/kernel)) forall)
(unmangle-types-in #:no-introduce (only-types-in hackett/private/prim/type))
(only-in (unmangle-types-in #:no-introduce #:only hackett/private/kernel) forall)
(unmangle-types-in #:no-introduce #:only hackett/private/prim/type)
(only-in hackett/private/prim/type
True False :: Nil
[Unit MkUnit] [Tuple MkTuple] [IO MkIO])
2 changes: 1 addition & 1 deletion hackett-lib/hackett/private/prim/type-provide.rkt
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
(postfix-in - racket/base)
(only-in hackett/private/base define-primop type)
(only-in hackett/private/kernel :)
(only-in (unmangle-types-in #:no-introduce (only-types-in hackett/private/kernel))
(only-in (unmangle-types-in #:no-introduce #:only hackett/private/kernel)
[#%app @%app]))

(provide typed-out)
82 changes: 12 additions & 70 deletions hackett-lib/hackett/private/type-reqprov.rkt
Original file line number Diff line number Diff line change
@@ -16,8 +16,8 @@
; using ‘for-type’, and Hackett’s ‘require’ implicitly surrounds its subforms with
; ‘unmangle-types-in’, so types are automatically injected into the proper namespace. This gets a bit
; trickier, however, when interoperating with Racket modules, which obviously do not have a notion of
; a type namespace. In this case, users must explicitly use ‘only-types-in’ or ‘unmangle-types-in’
; with the ‘#:no-introduce’ or ‘#:prefix’ options in order to flatten the two Hackett namespaces into
; a type namespace. In this case, users must explicitly use ‘unmangle-types-in’, possibly with the
; ‘#:only’, ‘#:no-introduce’, or ‘#:prefix’ options in order to flatten the two Hackett namespaces into
; Racket’s single one.

(require (for-syntax racket/base
@@ -29,77 +29,19 @@
racket/require
syntax/parse/define

(for-syntax hackett/private/typecheck))
(for-syntax hackett/private/typecheck
"mangle/mangle-identifier.rkt"
"mangle/mangle-reqprov.rkt"))

(provide for-type only-types-in unmangle-types-in)
(provide for-type unmangle-types-in)

(begin-for-syntax
(define mangled-type-regexp #rx"^#%hackett-type:(.+)$")
(define (unmangle-type-name name)
(and~> (regexp-match mangled-type-regexp name) second))
(define-values [type-id-mangler type-id-unmangler]
(make-id-mangler #:prefix "#%hackett-type:"
#:introducer type-namespace-introduce)))

(struct for-type-transformer ()
#:property prop:require-transformer
(λ (self)
(syntax-parser
[(_ require-spec ...)
#:do [(define-values [imports sources] (expand-import (syntax/loc this-syntax
(combine-in require-spec ...))))]
(values (for/list ([i (in-list imports)])
(struct-copy import i [local-id (type-namespace-introduce (import-local-id i))]))
sources)]))
#:property prop:provide-transformer
(λ (self)
(λ (stx modes)
(syntax-parse stx
[(_ {~optional {~and #:no-introduce no-introduce?}} provide-spec ...)
(for/list ([e (in-list (expand-export (syntax/loc this-syntax
(combine-out provide-spec ...))
modes))])
(struct-copy export e
[local-id (if (attribute no-introduce?)
(export-local-id e)
(type-namespace-introduce (export-local-id e)))]
[out-sym (~>> (export-out-sym e)
symbol->string
(string-append "#%hackett-type:")
string->symbol)]))])))))

(define-syntax for-type (for-type-transformer))

(define-syntax only-types-in
(make-require-transformer
(syntax-parser
[(_ require-spec ...)
(expand-import
#`(matching-identifiers-in #,mangled-type-regexp (combine-in require-spec ...)))])))
(define-syntax for-type
(make-mangling-provide-transformer type-id-mangler))

(define-syntax unmangle-types-in
(make-require-transformer
(syntax-parser
[(_ {~or {~optional {~or {~and #:no-introduce no-introduce?}
{~seq #:prefix prefix:id}}}}
require-spec ...)
#:do [(define-values [imports sources] (expand-import #'(combine-in require-spec ...)))]
(values (map (match-lambda
[(and i (import local-id src-sym src-mod-path mode req-mode orig-mode orig-stx))
(let* ([local-name (symbol->string (syntax-e local-id))]
[unmangled-type-name (unmangle-type-name local-name)])
(if unmangled-type-name
(let* ([prefixed-type-name
(if (attribute prefix)
(string-append (symbol->string (syntax-e #'prefix))
unmangled-type-name)
unmangled-type-name)]
[unmangled-id (datum->syntax local-id
(string->symbol prefixed-type-name)
local-id
local-id)])
(import (if (or (attribute no-introduce?)
(attribute prefix))
unmangled-id
(type-namespace-introduce unmangled-id))
src-sym src-mod-path mode req-mode orig-mode orig-stx))
i))])
imports)
sources)])))
(make-unmangling-require-transformer type-id-unmangler))
2 changes: 1 addition & 1 deletion hackett-lib/info.rkt
Original file line number Diff line number Diff line change
@@ -9,4 +9,4 @@
"syntax-classes-lib"
"threading-lib"))
(define build-deps
'())
'("rackunit-lib"))
2 changes: 1 addition & 1 deletion hackett-test/hackett/private/test.rkt
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
syntax/parse/define

hackett/private/type-reqprov
(prefix-in t: (unmangle-types-in #:no-introduce (only-types-in hackett)))
(prefix-in t: (unmangle-types-in #:no-introduce #:only hackett))
(only-in hackett [#%app @%app] module+ : Unit Tuple)
(only-in hackett/private/prim IO unsafe-run-io!)
hackett/private/prim/type-provide