I'm implementing a custom language in Racket in which I would like to provide an eval
procedure bound to the namespace of this custom language.
my-lang.rkt:
#lang racket
(provide #%module-begin #%top #%datum #%app)
(provide quote)
(provide (rename-out [a b] [my-eval eval]))
(define-namespace-anchor anchor)
(define ns (namespace-anchor->namespace anchor)) ; wrong namespace
(define (my-eval x) (eval x ns))
(define a 1)
test.rkt:
#lang s-exp "my-lang.rkt"
(eval 'a)
(eval 'b)
As implemented, since ns
is the namespace of my-lang.rkt, (eval 'a)
evaluates to 1
while (eval 'b)
fails.
I would like ns
to be bound to the namespace of test.rkt so that (eval 'a)
fails and (eval 'b)
returns 1
.
How should I define ns
?
Here's a way using parameter and macro. There might be a better way:
;; my-lang.rkt
#lang racket
(provide #%top #%datum #%app (rename-out [@#%module-begin #%module-begin])
quote
(rename-out [a b] [my-eval eval]))
(require syntax/parse/define
racket/splicing)
(define current-ns (make-parameter #f))
(define-syntax-parser @#%module-begin
[(_ . xs)
#'(#%module-begin
(define-namespace-anchor anchor)
(splicing-parameterize ([current-ns (namespace-anchor->namespace anchor)])
. xs))])
(define (my-eval x) (eval x (current-ns)))
(define a 1)
;; test.rkt
#lang s-exp "my-lang.rkt"
(eval 'b) ;=> 1
(eval 'a)
;; a: undefined;
;; cannot reference an identifier before its definition