PasteRack.org
Paste # 9771
2014-06-13 10:21:55

Fork as a new paste.

Paste viewed 656 times.


Embed:

Implementing declarations

  1. #lang racket
  2. (require racket/splicing racket/stxparam)
  3. (require (for-syntax syntax/parse racket/format))
  4.  
  5. ;;;
  6. ;;; IMPLEMENTED
  7. ;;;
  8.  
  9. ;;; This program implement three forms:
  10. ;;;   (declare x)              that declares that the symbol x is the name of a variable
  11. ;;;   vars                     which evaluates to a list of all declared variables
  12. ;;;                            at the point, where vars occurs
  13. ;;;   (let-var (x ...) body)   a local declaration, where the symbols x ...
  14. ;;;                            are declared in body, but not outside.
  15.  
  16. ;;; Example
  17.  
  18. ; Form:                               Result:
  19. ;   vars                               ()
  20. ;   (declare x)
  21. ;   vars                               (x)
  22. ;   (let-var (y) vars)                 (y x)
  23. ;   vars                               (x)
  24. ;   (let-var (y) (let-var z 1) vars)   (y x)
  25.  
  26. ;;;
  27. ;;; PROBLEM
  28. ;;;
  29.  
  30. ; i) How can I extend the definition of declare in order to
  31. ;    support declarations in a internal definition context?
  32.  
  33. ; That is, is there a way to get this interaction:
  34.  
  35. ; Form:                                                 Result:
  36. ;   vars                                                 ()
  37. ;   (declare x)
  38. ;   vars                                                 (x)
  39. ;   (let () (declare y) vars)                            (y x)
  40. ;   vars                                                 (y)
  41. ;   (let ()
  42. ;     (declare y)
  43. ;     (let () (declare z) 1)
  44. ;     vars)                                              (y x)
  45.  
  46.  
  47. (begin-for-syntax
  48.   ; Global variables are simply stored in a compile time variable
  49.   (define globals '()))
  50.  
  51. ; At expansion start there is only global variables, so
  52. ; vars simply returns a quoted copy of the symbols collected in globals
  53. (define-syntax-parameter vars (λ(stx) #`'#,globals))
  54.  
  55. ; Local variables on the other hand must be kept in a syntax parameter
  56. ; to keep the list of locally declared variable around at syntax transformation time.
  57. (define-syntax-parameter locals '())
  58.  
  59.  
  60. (define-syntax (orig-declare stx)
  61.   ; A simple version of declare (here named orig-declare) simply adds
  62.   ; declared variables to the global list.
  63.   (syntax-parse stx
  64.     [(_ v)
  65.      (define var (syntax->datum #'v))
  66.      (unless (member var globals)
  67.        (set! globals (cons var globals)))
  68.      #'(void)]))
  69.  
  70.  
  71. ; The following tests reveals that everything works as expected:
  72.  
  73. ; Expression     Expected
  74. vars                ;  ()
  75. (orig-declare x)    ;
  76. vars                ;  (x)
  77. (orig-declare x)    ;
  78. vars                ;  (x)
  79. (orig-declare y)    ;
  80. vars                ;  (y x)
  81.  
  82.  
  83. ; Locally declared variables are implemented using syntax-parameterize.
  84. ; Both the user facing syntax   vars  and the list of locally
  85. ; declared are adjusted with the help of syntax-parameterize.
  86.  
  87. ; (let-var (var ...) body ...)
  88. ;   evaluate body in an environment where var ... are declared variables
  89. (define-syntax (let-var stx)
  90.   (syntax-parse stx
  91.     [(_ () body ...)
  92.      #'(let () body ...)]
  93.     [(_ (v:id vs:id ...) body ...)
  94.      (let ()
  95.        (define var (syntax->datum #'v))
  96.        (define old-locals (syntax-parameter-value #'locals))
  97.        (define new-locals (cons var old-locals))
  98.        #`(syntax-parameterize ([vars (λ (stx) #''#,(append new-locals globals))])
  99.            (syntax-parameterize ([locals '#,new-locals])
  100.              (let-var (vs ...) body ...))))]))
  101.  
  102.  
  103. ; Expression                             Expected
  104. (let-var (a) vars)                    ;  (  a y x)
  105. (let-var (a b) vars)                  ;  (b a y x)
  106. (let-var (a) (let-var (b) vars))      ;  (b a y x)
  107. (let-var (a) (let-var (b) 7) vars)    ;  (  a y x)
  108.  
  109.  
  110. ;;;
  111. ;;; The hope was to copy the ideas used in let-var to implement
  112. ;;; declarations in an internal definition context.
  113.  
  114. ;;; The point where I am stuck:
  115. ;;;   syntax-parameterize can adjust the meaning of locals and vars in a given body
  116. ;;;   But in an internal definition context, the meaning of locals and vars
  117. ;;;   must be adjusted in the rest of the internal definition context,
  118. ;;;   so at the point where (declare x) is expanded, there is no access to the "body".
  119.  
  120. (define-syntax (declare stx)
  121.   (syntax-parse stx
  122.     [(_ v)
  123.      (define var (syntax->datum #'v))
  124.      (define ctx (syntax-local-context))
  125.      (cond
  126.        [(eq? ctx 'top-level)
  127.         ; outside any module, definition or expression
  128.         ; (except as a subsexpression in a top-level begin)
  129.         ; i.e. think repl...
  130.         (error 'declare "the top-level context not supported (yet?)")]
  131.        [(eq? ctx 'module-begin)
  132.         ; inside the body of a module as the only form within the module
  133.         (error 'declare "the module-begin context not supported (yet?)")]
  134.        [(eq? ctx 'expression)
  135.         ; in a context where only expressions are allowed
  136.         (error 'declare "declarations can not appear as expressions")]
  137.        [(eq? ctx 'module)
  138.         ; in a module (inside the module-begin layer)
  139.         (unless (member var globals)
  140.           (set! globals (cons var globals)))
  141.         #'(void)]
  142.        [(list? ctx) ; internal definition context
  143.         ; in a nested context that allows both definitions and expressions
  144.         ; e.g. the body of a let expression is an internal definition context
  145.         ; For let and friends, a defintion in an internal definition context
  146.         ; is a equivalent to local binding via letrec-syntaxes+values.
  147.         ; Each body is partially expanded into one of:
  148.         ;   i) define-values
  149.         ;  ii) define-syntaxes
  150.         ; iii) primitive expression other than begin
  151.         ;  iv) a begin form (which is spliced in, and the newly-spliced subforms
  152.         ;      are also partially expanded)
  153.         ; The definitions and expressions are then rewritten into a letrec-syntaxes+values form
  154.  
  155.         ; Note: A (define-syntax-parameter ...) expands into define-syntaxes.
  156.         ;       But what about syntax-parameterize ?
  157.         (define var (syntax->datum #'v))
  158.         (define old-locals (unbox (syntax-parameter-value #'locals)))
  159.         (define new-locals (cons var old-locals))
  160.         (displayln new-locals)
  161.         #'(void) ; <- What to write here?
  162.         ]
  163.        [else (error 'declare (~a "expansion reached unhandled expansion context " ctx))])]))

=>