Skip to content

Commit 42cf771

Browse files
committed
Initial attempt at : declarations for val definitions
1 parent 9be5c6f commit 42cf771

File tree

1 file changed

+99
-32
lines changed

1 file changed

+99
-32
lines changed

hackett-lib/hackett/private/base.rkt

Lines changed: 99 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
syntax/parse/experimental/template
77
syntax/intdef
88
syntax/srcloc
9+
syntax/parse/class/local-value
910
threading)
1011
(postfix-in - (combine-in racket/base
1112
racket/promise))
@@ -324,6 +325,28 @@
324325

325326
;; ---------------------------------------------------------------------------------------------------
326327

328+
(begin-for-syntax
329+
; fixity : [Maybe Fixity]
330+
(struct val-decl [internal-id type fixity]
331+
#:property prop:procedure
332+
(λ (this stx)
333+
(match-define (val-decl x- type _) this)
334+
((make-typed-var-transformer x- type) stx))
335+
#:property prop:infix-operator
336+
(λ (this) (val-decl-fixity this)))
337+
338+
(define-syntax-class id/val-decl
339+
#:attributes [internal-id type.expansion type.scoped-binding-introducer]
340+
[pattern (~var x (local-value val-decl?))
341+
#:attr internal-id
342+
(syntax-local-introduce
343+
(val-decl-internal-id (attribute x.local-value)))
344+
#:with type:type
345+
(syntax-local-introduce
346+
(val-decl-type (attribute x.local-value)))]))
347+
348+
;; ---------------------------------------------------------------------------------------------------
349+
327350
(define-syntax-parser @%module-begin
328351
[(_ form ...)
329352
(~> (local-expand (value-namespace-introduce
@@ -343,20 +366,48 @@
343366
[(_ . x)
344367
(raise-syntax-error #f "literal not supported" #'x)])
345368

346-
(define-syntax-parser :
347-
; The #:exact option prevents : from performing context reduction. This is not normally important,
348-
; but it is required for forms that use : to ensure an expression has a particular shape in order to
349-
; interface with untyped (i.e. Racket) code, and therefore the resulting type is ignored. For
350-
; example, the def form wraps an expression in its expansion with :, but it binds the actual
351-
; identifier to a syntax transformer that attaches the type directly. Therefore, it needs to perform
352-
; context reduction itself prior to expanding to :, and it must use #:exact.
353-
[(_ e {~type t:type} {~optional {~and #:exact exact?}})
354-
#:with t_reduced (if (attribute exact?)
355-
#'t.expansion
356-
(type-reduce-context #'t.expansion))
357-
(attach-type #`(let-values- ([() t.residual])
358-
#,(τ⇐! ((attribute t.scoped-binding-introducer) #'e) #'t_reduced))
359-
#'t_reduced)])
369+
;; The `:` form behaves differently in an expression context vs. a
370+
;; module context by dispatching on (syntax-local-context).
371+
(define-syntax :
372+
(λ (stx)
373+
(match (syntax-local-context)
374+
; In an expression context, `:` annotates an expression with
375+
; an expected type.
376+
['expression
377+
(syntax-parse stx
378+
; The #:exact option prevents : from performing context reduction. This is not normally important,
379+
; but it is required for forms that use : to ensure an expression has a particular shape in order to
380+
; interface with untyped (i.e. Racket) code, and therefore the resulting type is ignored. For
381+
; example, the def form wraps an expression in its expansion with :, but it binds the actual
382+
; identifier to a syntax transformer that attaches the type directly. Therefore, it needs to perform
383+
; context reduction itself prior to expanding to :, and it must use #:exact.
384+
[(_ e {~type t:type} {~optional {~and #:exact exact?}})
385+
#:with t_reduced (if (attribute exact?)
386+
#'t.expansion
387+
(type-reduce-context #'t.expansion))
388+
(attach-type #`(let-values- ([() t.residual])
389+
#,(τ⇐! ((attribute t.scoped-binding-introducer) #'e) #'t_reduced))
390+
#'t_reduced)])]
391+
392+
; In other contexts, such as module-level bindings or
393+
; in the REPL, : is a type declaration for `x`, and
394+
; will be understood by `def`.
395+
[_
396+
(syntax-parse stx
397+
[(_ x:id {~type t:type}
398+
{~alt {~optional {~and #:exact exact?}}
399+
{~optional f:fixity-annotation}}
400+
...)
401+
#:with x- (generate-temporary #'x)
402+
#:with fixity (attribute f.fixity)
403+
#:with t_reduced (if (attribute exact?)
404+
#'t.expansion
405+
(type-reduce-context #'t.expansion))
406+
#'(define-syntax x
407+
(let-values ([() t.residual])
408+
(val-decl (quote-syntax x-)
409+
(quote-syntax t_reduced)
410+
'fixity)))])])))
360411

361412
(define-syntax-parser λ1
362413
[(_ x:id e:expr)
@@ -383,31 +434,47 @@
383434

384435
(define-syntax-parser def
385436
#:literals [:]
386-
[(_ id:id
387-
{~or {~once {~seq {~and : {~var :/use}} {~type t:type}
388-
{~optional {~and #:exact exact?}}}}
389-
{~optional fixity:fixity-annotation}}
390-
...
437+
[(_ x:id/val-decl e:expr)
438+
#:with x- #'x.internal-id
439+
(syntax-property
440+
#`(define- x- (: #,((attribute x.type.scoped-binding-introducer)
441+
#'e)
442+
x.type.expansion
443+
#:exact))
444+
'disappeared-use
445+
(syntax-local-introduce #'x))]
446+
447+
[(_ x:id {~and : {~var :/use}} type:expr
448+
{~and {~seq stuff ...}
449+
{~seq {~alt {~optional {~and #:exact exact?}}
450+
{~optional f:fixity-annotation}}
451+
...}}
391452
e:expr)
392-
#:with id- (generate-temporary #'id)
393-
#:with t_reduced (if (attribute exact?) #'t.expansion (type-reduce-context #'t.expansion))
394-
#`(begin-
395-
#,(indirect-infix-definition
396-
#'(define-syntax- id (make-typed-var-transformer #'id- (quote-syntax t_reduced)))
397-
(attribute fixity.fixity))
398-
(define- id- (:/use #,((attribute t.scoped-binding-introducer) #'e) t_reduced #:exact)))]
453+
#'(begin-
454+
(:/use x type stuff ...)
455+
(def x e))]
456+
399457
[(_ id:id
400-
{~optional fixity:fixity-annotation}
458+
{~and {~seq fixity-stuff ...}
459+
{~optional fixity:fixity-annotation}}
401460
e:expr)
402-
#:with x^ (generate-temporary)
461+
#:with x^ (generate-temporary #'z)
403462
#:with t_e #'(#%type:wobbly-var x^)
404463
#:do [(match-define-values [(list id-) e-] (τ⇐/λ! #'e #'t_e (list (cons #'id #'t_e))))]
405464
#:with t_gen (type-reduce-context (generalize (apply-current-subst #'t_e)))
465+
#:with id-/gen (attach-type id- #'t_gen)
406466
#`(begin-
407-
#,(indirect-infix-definition
408-
#`(define-syntax- id (make-typed-var-transformer (quote-syntax #,id-) (quote-syntax t_gen)))
409-
(attribute fixity.fixity))
410-
(define- #,id- #,e-))])
467+
(: id t_gen fixity-stuff ... #:exact)
468+
(define/val-decl id
469+
(let-syntax ([id-/gen
470+
(make-rename-transformer (quote-syntax id))])
471+
#,e-)))])
472+
473+
(define-syntax-parser define/val-decl
474+
[(_ x:id/val-decl rhs)
475+
#:with x- #'x.internal-id
476+
#'(define- x- rhs)])
477+
411478

412479
(begin-for-syntax
413480
(struct todo-item (full summary) #:prefab))

0 commit comments

Comments
 (0)