Hi All, In order to add linear equation syntax to MetaPict I need to understand how implement declarations in an internal definition context. For practice purposes I have written the following small program. So far global declarations and local declaration via a let-var binding construct works. I am now attempting to transfer the methods used in let-var into an implementation of declarations that work in an internal definition context. Unfortunately I am stuck.
In the definition of let-var I have used syntax-parameterize and I can't figure what to do in an internal definition context. Any help is appreciated. I have inserted and attached the program below, but there is a pretty, color version at PasteRack: http://pasterack.org/pastes/9771 /Jens Axel #lang racket (require racket/splicing racket/stxparam) (require (for-syntax syntax/parse racket/format)) ;;; ;;; IMPLEMENTED ;;; ;;; This program implement three forms: ;;; (declare x) that declares that the symbol x is the name of a variable ;;; vars which evaluates to a list of all declared variables ;;; at the point, where vars occurs ;;; (let-var (x ...) body) a local declaration, where the symbols x ... ;;; are declared in body, but not outside. ;;; Example ; Form: Result: ; vars () ; (declare x) ; vars (x) ; (let-var (y) vars) (y x) ; vars (x) ; (let-var (y) (let-var z 1) vars) (y x) ;;; ;;; PROBLEM ;;; ; i) How can I extend the definition of declare in order to ; support declarations in a internal definition context? ; That is, is there a way to get this interaction: ; Form: Result: ; vars () ; (declare x) ; vars (x) ; (let () (declare y) vars) (y x) ; vars (y) ; (let () ; (declare y) ; (let () (declare z) 1) ; vars) (y x) (begin-for-syntax ; Global variables are simply stored in a compile time variable (define globals '())) ; At expansion start there is only global variables, so ; vars simply returns a quoted copy of the symbols collected in globals (define-syntax-parameter vars (λ(stx) #`'#,globals)) ; Local variables on the other hand must be kept in a syntax parameter ; to keep the list of locally declared variable around at syntax transformation time. (define-syntax-parameter locals '()) (define-syntax (orig-declare stx) ; A simple version of declare (here named orig-declare) simply adds ; declared variables to the global list. (syntax-parse stx [(_ v) (define var (syntax->datum #'v)) (unless (member var globals) (set! globals (cons var globals))) #'(void)])) ; The following tests reveals that everything works as expected: ; Expression Expected vars ; () (orig-declare x) ; vars ; (x) (orig-declare x) ; vars ; (x) (orig-declare y) ; vars ; (y x) ; Locally declared variables are implemented using syntax-parameterize. ; Both the user facing syntax vars and the list of locally ; declared are adjusted with the help of syntax-parameterize. ; (let-var (var ...) body ...) ; evaluate body in an environment where var ... are declared variables (define-syntax (let-var stx) (syntax-parse stx [(_ () body ...) #'(let () body ...)] [(_ (v:id vs:id ...) body ...) (let () (define var (syntax->datum #'v)) (define old-locals (syntax-parameter-value #'locals)) (define new-locals (cons var old-locals)) #`(syntax-parameterize ([vars (λ (stx) #''#,(append new-locals globals))]) (syntax-parameterize ([locals '#,new-locals]) (let-var (vs ...) body ...))))])) ; Expression Expected (let-var (a) vars) ; ( a y x) (let-var (a b) vars) ; (b a y x) (let-var (a) (let-var (b) vars)) ; (b a y x) (let-var (a) (let-var (b) 7) vars) ; ( a y x) ;;; ;;; The hope was to copy the ideas used in let-var to implement ;;; declarations in an internal definition context. ;;; The point where I am stuck: ;;; syntax-parameterize can adjust the meaning of locals and vars in a given body ;;; But in an internal definition context, the meaning of locals and vars ;;; must be adjusted in the rest of the internal definition context, ;;; so at the point where (declare x) is expanded, there is no access to the "body". (define-syntax (declare stx) (syntax-parse stx [(_ v) (define var (syntax->datum #'v)) (define ctx (syntax-local-context)) (cond [(eq? ctx 'top-level) ; outside any module, definition or expression ; (except as a subsexpression in a top-level begin) ; i.e. think repl... (error 'declare "the top-level context not supported (yet?)")] [(eq? ctx 'module-begin) ; inside the body of a module as the only form within the module (error 'declare "the module-begin context not supported (yet?)")] [(eq? ctx 'expression) ; in a context where only expressions are allowed (error 'declare "declarations can not appear as expressions")] [(eq? ctx 'module) ; in a module (inside the module-begin layer) (unless (member var globals) (set! globals (cons var globals))) #'(void)] [(list? ctx) ; internal definition context ; in a nested context that allows both definitions and expressions ; e.g. the body of a let expression is an internal definition context ; For let and friends, a defintion in an internal definition context ; is a equivalent to local binding via letrec-syntaxes+values. ; Each body is partially expanded into one of: ; i) define-values ; ii) define-syntaxes ; iii) primitive expression other than begin ; iv) a begin form (which is spliced in, and the newly-spliced subforms ; are also partially expanded) ; The definitions and expressions are then rewritten into a letrec-syntaxes+values form ; Note: A (define-syntax-parameter ...) expands into define-syntaxes. ; But what about syntax-parameterize ? (define var (syntax->datum #'v)) (define old-locals (unbox (syntax-parameter-value #'locals))) (define new-locals (cons var old-locals)) (displayln new-locals) #'(void) ; <- What to write here? ] [else (error 'declare (~a "expansion reached unhandled expansion context " ctx))])]))
example-of-declare-and-letvar.rkt
Description: Binary data
____________________ Racket Users list: http://lists.racket-lang.org/users