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

From: Chrisophe Vandenberghe (chvndb at gmail.com)
Date: Tue Feb 25 09:54:56 EST 2014

Hey guys,

(first time poster)

I have been learning how the Racket Syntax Framework works and trying to make a custom language. What I am currently trying to make is a small Object Oriented language which has classes and so on. I don't want to use the built-in classes as I want to alter the OO meaning once I got my language going … Anyway, the goal would be to have something similar to this:

(CLASS
	(FIELD x 1)
	(FIELD y 1)
	(METHOD (x?) x)
	(METHOD (x! new) (set! x new)))

Both fields and methods are kept in a hash table for lookup. So what I would want is that in the above method "x?" the identifier x is recognised as not "lexically bound" and thus refers to the field x. So during syntax transformation I can take some action to fetch the value of that field in the field lookup table. However, I can't seem to make the test for "lexically bound" work. It always returns false. So take for example the method "x!", in that case it would fail to recognise that the value of the identifier "new" is given by the local parameter and would also try to lookup new in the field lookup table of the object. However, it should only try to lookup x.

I guess it's hard to grasp what I mean, so I have made a simplified version of what I have. Remember that I have stripped down most to make it more understandable, so this code does not create classes in any way but it is structured exactly like my original code. I might therefore seem weird to use so many syntax-classes as they are superfluous here, but in my implementation there is a lot more stuff going on which require them.


#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-syntax (CLASS stx)
  
  ;; Literal
  
  (define-syntax-class (literal)
    (pattern value:boolean)
    (pattern value:char)
    (pattern value:integer)
    (pattern value:number)
    (pattern value:str))
  
  ;; Object Expression (validates all expressions inside a class)
    
  (define-syntax-class (class-expr)
    
    #:datum-literals (define)
    #:commit
    
    (pattern value:literal
             #:with <value> #'value)
    (pattern value:id
             #:with <value> (begin (display #'value) (newline)
                                   (display (lexically-bound? #'value)) (newline)
                                   (if (lexically-bound? #'value) #'value #'(void))))
    (pattern (define name:id arg:class-expr)
             #:with <value> #'(define name arg.<value>))
    (pattern (operator:id arg:class-expr ...)
             #:with <value> #'(operator arg.<value> ...)))
  
  ;; Method Class
  
  (define-syntax-class (class-method)
      
      #:datum-literals (METHOD)
      
      (pattern (METHOD (name:id arg:id ...) body:class-expr ...)
               #:with <value> #'(define (name arg ...) body.<value> ...)))
  
  ;;;;; Class Parser
  
  (syntax-parse 
   stx
   
   #:datum-literals (CLASS)
   
   [(CLASS <method>:class-method)
    #'<method>.<value>]))



;; Example Case

(CLASS
 (METHOD (test a b) (define c 1) a b c d))


In the example above, what I want is that a, b and c are recognised as "lexically bound" and d is not. Then I can transform d to something that fetches the "d" entry in the fields hash map of the object. However, when this code is run all 4 are returned as unbound.

If I would add:

(define a 1)
(define b 1)
(define c 1)
(define d 1)

before the CLASS definition then it works, so the check to see if they are lexically bound should be correct. Therefore, I am thinking that I am approaching my problem incorrectly.


Thanks for any response,

Christophe


p.s. If I make incorrect use of syntax-classes feel free to let me know.

Posted on the users mailing list.