Hi, I found a solution to the first problem where the parameter of the method are now recognised as "lexically bound". However, it seems like a dirty hack as i have to pass the arg list explicitly when checking the body expressions. Furthermore, this does not solve the issue when methods contain id bindings in the body. Any suggestions? I could keep a list during syntax parsing and whenever a define is found it adds to that list and then simply check if the id is in that list, but again that seems a very dirty hack.
#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)) ;; Arg List (define-splicing-syntax-class (arg-list) (pattern (~seq arg:id ...))) ;; 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> (begin ;(display #'value) (newline) ;(display (lexically-bound? #'value)) (newline) ;(display (local-parameter? #'value args)) (newline) (if (or (lexically-bound? #'value) (local-parameter? #'value args)) #'value #'(void)))) (pattern (define name:id (~var arg (class-expr args))) #:with <value> #'(define name arg.<value>)) (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) On 25 Feb 2014, at 15:54, Chrisophe Vandenberghe <chv...@gmail.com> wrote: > 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. ____________________ Racket Users list: http://lists.racket-lang.org/users