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 <[email protected]> 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