|
6 | 6 | syntax/parse/experimental/template |
7 | 7 | syntax/intdef |
8 | 8 | syntax/srcloc |
| 9 | + syntax/parse/class/local-value |
9 | 10 | threading) |
10 | 11 | (postfix-in - (combine-in racket/base |
11 | 12 | racket/promise)) |
|
324 | 325 |
|
325 | 326 | ;; --------------------------------------------------------------------------------------------------- |
326 | 327 |
|
| 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 | + |
327 | 350 | (define-syntax-parser @%module-begin |
328 | 351 | [(_ form ...) |
329 | 352 | (~> (local-expand (value-namespace-introduce |
|
343 | 366 | [(_ . x) |
344 | 367 | (raise-syntax-error #f "literal not supported" #'x)]) |
345 | 368 |
|
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)))])]))) |
360 | 411 |
|
361 | 412 | (define-syntax-parser λ1 |
362 | 413 | [(_ x:id e:expr) |
|
383 | 434 |
|
384 | 435 | (define-syntax-parser def |
385 | 436 | #: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 | + ...}} |
391 | 452 | 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 | + |
399 | 457 | [(_ id:id |
400 | | - {~optional fixity:fixity-annotation} |
| 458 | + {~and {~seq fixity-stuff ...} |
| 459 | + {~optional fixity:fixity-annotation}} |
401 | 460 | e:expr) |
402 | | - #:with x^ (generate-temporary) |
| 461 | + #:with x^ (generate-temporary #'z) |
403 | 462 | #:with t_e #'(#%type:wobbly-var x^) |
404 | 463 | #:do [(match-define-values [(list id-) e-] (τ⇐/λ! #'e #'t_e (list (cons #'id #'t_e))))] |
405 | 464 | #:with t_gen (type-reduce-context (generalize (apply-current-subst #'t_e))) |
| 465 | + #:with id-/gen (attach-type id- #'t_gen) |
406 | 466 | #`(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 | + |
411 | 478 |
|
412 | 479 | (begin-for-syntax |
413 | 480 | (struct todo-item (full summary) #:prefab)) |
|
0 commit comments