[racket] [Racket Syntax] Check if identifier is lexically bound

From: Chrisophe Vandenberghe (chvndb at gmail.com)
Date: Mon Mar 3 15:06:28 EST 2014

Exactly what I was thinking, but couldn't find a clear way of doing it the "right" way. I'll have a read through the paper when I find the time and report back when I have found a better solution. It works for now with my fix, so it can wait as I need to finish my implementation ASAP.

Thx for the replies.

Christophe

On 03 Mar 2014, at 20:47, Sam Tobin-Hochstadt <samth at cs.indiana.edu> wrote:

> I'm pretty sure that this is just implementing an internal definition
> context inside the `METHOD` macro, and should therefore use the
> techniques discussed in this paper:
> http://www.cs.utah.edu/plt/expmodel-6/
> 
> In general, trying to traverse the body of the `METHOD` before
> expanding it will never actually do the right thing -- the only way to
> understand pre-expansion Racket forms is to expand them.
> 
> Sam
> 
> On Mon, Mar 3, 2014 at 2:42 PM, Matthias Felleisen <matthias at ccs.neu.edu> wrote:
>> 
>> Okay, got it.
>> 
>> (1) I can't see better ways to accomplish what you want, other than turning identifiers into symbols and looking them up in a hash table (which defaults to void).
>> 
>> (2) I admit it's ugly to keep track of lexical vars like that. Chez used to have fluid-syntax-let, and it would have helped a bit here. We don't have it, or I am too out of it today to find something similar.
>> 
>> Perhaps someone from the unstable/syntax family can help.
>> 
>> -- Matthias
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> On Mar 3, 2014, at 2:18 PM, Chrisophe Vandenberghe <chvndb at gmail.com> wrote:
>> 
>>> If  you run the code (the last one I posted) it outputs '(1 2 #<void> #<void>). But, I want it to output '(1 2 1 #<void>).
>>> There is a (define c 1) which is not recognised in my implementation.
>>> 
>>> The only solution I have found so far is to keep a list during syntax expansion which keeps track of local definitions and which is reset when a new METHOD is encountered. Below is the result code which outputs what I want. This allows me to do more useful stuff then to return void when the identifier is not found.
>>> 
>>> Is it really that hard to understand? Should i re-write my code and not use syntax-classes? I know the example is unclear cause this syntax simply returns a method, but that is not the point. My entire implementation is 500 LOC, so I had to simplify it to post it.
>>> 
>>> #lang racket
>>> 
>>> (require (for-syntax syntax/parse))
>>> 
>>> (define-for-syntax (lexically-bound? stx)
>>> (define expanded (local-expand stx (syntax-local-context) #f))
>>> (and (identifier? expanded)
>>>      (not (eq? #f (identifier-binding expanded)))))
>>> 
>>> (define-for-syntax (local-parameter? stx pars-stx)
>>> (ormap (lambda (par) (bound-identifier=? stx par)) (syntax-e pars-stx)))
>>> 
>>> (define-syntax (CLASS stx)
>>> 
>>> ;; Literal
>>> 
>>> (define-syntax-class (literal)
>>>   (pattern value:boolean)
>>>   (pattern value:char)
>>>   (pattern value:integer)
>>>   (pattern value:number)
>>>   (pattern value:str))
>>> 
>>> ;; Current local definition (used during every method expansion)
>>> 
>>> (define current-local-defs '())
>>> 
>>> ;; Arg List
>>> 
>>> (define-splicing-syntax-class (arg-list)
>>>   (pattern (~seq arg:id ...)
>>>            #:do [(set! current-local-defs '())]))
>>> 
>>> ;; Class Expression (validates all expressions inside a class)
>>> 
>>> (define-syntax-class (class-expr args)
>>> 
>>>   #:datum-literals (define)
>>>   #:commit
>>> 
>>>   (pattern value:literal
>>>            #:with <value> #'value)
>>>   (pattern value:id
>>>            #:with <value> (if (or (lexically-bound? #'value)
>>>                                   (local-parameter? #'value args)
>>>                                   (member (syntax-e #'value) current-local-defs))
>>>                               #'value
>>>                               #'(void)))
>>>   (pattern (define name:id (~var arg (class-expr args)))
>>>            #:with <value> #'(define name arg.<value>)
>>>            #:do [(set! current-local-defs (cons (syntax-e #'name) current-local-defs))])
>>>   (pattern (operator:id (~var arg (class-expr args)) ...)
>>>            #:with <value> #'(operator arg.<value> ...)))
>>> 
>>> ;; Method Class
>>> 
>>> (define-syntax-class (class-method)
>>> 
>>>   #:datum-literals (METHOD)
>>> 
>>>   (pattern (METHOD (name:id (~var arg-list arg-list)) (~var body (class-expr #'arg-list)) ...)
>>>            #:with <value> #'(define (name arg-list.arg ...) body.<value> ...)))
>>> 
>>> ;;;;; Class Parser
>>> 
>>> (syntax-parse
>>>  stx
>>> 
>>>  #:datum-literals (CLASS)
>>> 
>>>  [(CLASS <method>:class-method)
>>>   #'<method>.<value>]))
>>> 
>>> (CLASS
>>> 
>>> (METHOD (test a b) (define c 1) (list a b c d)))
>>> 
>>> (test 1 2)
>> 
>> 
>> ____________________
>>  Racket Users list:
>>  http://lists.racket-lang.org/users



Posted on the users mailing list.