Skip to content

Commit ca30c7c

Browse files
committed
Add declarations for val definitions
1 parent f5a080e commit ca30c7c

File tree

3 files changed

+98
-22
lines changed

3 files changed

+98
-22
lines changed

hackett-lib/hackett/private/base.rkt

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
syntax/parse/experimental/template
77
syntax/intdef
88
syntax/srcloc
9-
threading)
9+
syntax/parse/class/local-value
10+
threading
11+
serialize-syntax-introducer)
1012
(postfix-in - (combine-in racket/base
1113
racket/promise))
1214
racket/stxparam
@@ -26,7 +28,7 @@
2628
@%superclasses-key @%dictionary-placeholder @%with-dictionary #%defer-expansion
2729
define-primop define-base-type
2830
-> Integer Double String
29-
: λ1 def let letrec todo!)
31+
: λ1 def let letrec todo!)
3032

3133
(define-base-type Integer)
3234
(define-base-type Double)
@@ -324,6 +326,37 @@
324326

325327
;; ---------------------------------------------------------------------------------------------------
326328

329+
(begin-for-syntax
330+
; Instances of this struct are created by `⋮` when declaring the types of bindings
331+
; seperately from their definitions. When a binding is defined (with `def` or related
332+
; forms), it searches for a `binding-declaration` and fills in `internal-id` with the
333+
; actual definition. The `type` field is used as the expected type of the definition.
334+
; fixity : [Maybe Fixity]
335+
(struct binding-declaration [internal-id type scoped-binding-introducer fixity]
336+
#:property prop:procedure
337+
(λ (this stx)
338+
(match-define (binding-declaration x- type _ _) this)
339+
((make-typed-var-transformer x- type) stx))
340+
#:property prop:infix-operator
341+
(λ (this) (binding-declaration-fixity this)))
342+
343+
(define-syntax-class id/binding-declaration
344+
#:attributes [internal-id type scoped-binding-introducer fixity]
345+
[pattern (~var x (local-value binding-declaration?))
346+
#:do [(match-define (binding-declaration x-* type* sbi* fixity*)
347+
(attribute x.local-value))]
348+
#:attr internal-id (syntax-local-introduce x-*)
349+
#:with type (syntax-local-introduce type*)
350+
#:attr scoped-binding-introducer (deserialize-syntax-introducer sbi*)
351+
#:attr fixity fixity*]))
352+
353+
(define-syntax-parser define/binding-declaration
354+
[(_ x:id/binding-declaration rhs)
355+
#:with x- #'x.internal-id
356+
#'(define- x- rhs)])
357+
358+
;; ---------------------------------------------------------------------------------------------------
359+
327360
(define-syntax-parser @%module-begin
328361
[(_ form ...)
329362
(~> (local-expand (value-namespace-introduce
@@ -343,6 +376,7 @@
343376
[(_ . x)
344377
(raise-syntax-error #f "literal not supported" #'x)])
345378

379+
;; The `:` form annotates an expression with an expected type.
346380
(define-syntax-parser :
347381
; The #:exact option prevents : from performing context reduction. This is not normally important,
348382
; but it is required for forms that use : to ensure an expression has a particular shape in order to
@@ -358,6 +392,36 @@
358392
#,(τ⇐! ((attribute t.scoped-binding-introducer) #'e) #'t_reduced))
359393
#'t_reduced)])
360394

395+
;; The `⋮` form declares that an id will be defined with an expected type.
396+
;; For example:
397+
;; (⋮ x τ)
398+
;; (def x e)
399+
;; Defines `x` with type `τ` to be equal to the value produced by `e`,
400+
;; which must produce
401+
(define-syntax
402+
(λ (stx)
403+
(syntax-parse stx
404+
[(_ x:id {~type t:type}
405+
{~alt {~optional {~and #:exact exact?}}
406+
{~optional f:fixity-annotation}}
407+
...)
408+
#:with x- (generate-temporary #'x)
409+
#:with exct? (and (attribute exact?) #true)
410+
#:with fixity (attribute f.fixity)
411+
#:with t_reduced (if (attribute exact?)
412+
#'t.expansion
413+
(type-reduce-context #'t.expansion))
414+
#:with sbi (serialize-syntax-introducer
415+
(attribute t.scoped-binding-introducer))
416+
#`(begin-
417+
(define-values- [] t.residual)
418+
(define-syntax- x
419+
(binding-declaration
420+
(quote-syntax x-)
421+
(quote-syntax t_reduced)
422+
(quote-syntax sbi)
423+
'fixity)))])))
424+
361425
(define-syntax-parser λ1
362426
[(_ x:id e:expr)
363427
#:do [(define t (get-expected this-syntax))]
@@ -383,31 +447,42 @@
383447

384448
(define-syntax-parser def
385449
#: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-
...
450+
[(_ x:id/binding-declaration e:expr)
451+
#:with x- #'x.internal-id
452+
(syntax-property
453+
#`(define- x-
454+
(: #,((attribute x.scoped-binding-introducer) #'e)
455+
x.type
456+
#:exact))
457+
'disappeared-use
458+
(syntax-local-introduce #'x))]
459+
460+
[(_ x:id : type:expr
461+
{~and {~seq stuff ...}
462+
{~seq {~alt {~optional {~and #:exact exact?}}
463+
{~optional f:fixity-annotation}}
464+
...}}
391465
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)))]
466+
#'(begin-
467+
(⋮ x type stuff ...)
468+
(def x e))]
469+
399470
[(_ id:id
400-
{~optional fixity:fixity-annotation}
471+
{~and {~seq fixity-stuff ...}
472+
{~optional fixity:fixity-annotation}}
401473
e:expr)
402-
#:with x^ (generate-temporary)
474+
#:with x^ (generate-temporary #'z)
403475
#:with t_e #'(#%type:wobbly-var x^)
404476
#:do [(match-define-values [(list id-) e-] (τ⇐/λ! #'e #'t_e (list (cons #'id #'t_e))))]
405477
#:with t_gen (type-reduce-context (generalize (apply-current-subst #'t_e)))
478+
#:with id-/gen (attach-type id- #'t_gen)
406479
#`(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-))])
480+
(⋮ id t_gen fixity-stuff ... #:exact)
481+
(define/binding-declaration id
482+
(let-syntax ([id-/gen
483+
(make-rename-transformer (quote-syntax id))])
484+
#,e-)))])
485+
411486

412487
(begin-for-syntax
413488
(struct todo-item (full summary) #:prefab))

hackett-lib/hackett/private/kernel.rkt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
[λ lambda])
2121
#%require/only-types combine-in except-in only-in prefix-in rename-in
2222
provide combine-out except-out prefix-out rename-out for-type module+
23-
: def λ let letrec todo!
23+
: def λ let letrec todo!
2424
(for-type #:no-introduce-> => Integer Double String
2525
(rename-out [@%top #%top]
2626
[#%type:app #%app]

hackett-lib/info.rkt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"curly-fn-lib"
88
"data-lib"
99
"syntax-classes-lib"
10-
"threading-lib"))
10+
"threading-lib"
11+
"serialize-syntax-introducer"))
1112
(define build-deps
1213
'())

0 commit comments

Comments
 (0)