简体   繁体   中英

Convert String of Racket Source Code into Racket Code

I'm writing a system where a client sends code to a server (implemented in racket) for execution. The code is received as a string. I need to convert that string into the racket code that it represents and execute it. Any definitions inside of the code need to be available after the code is extracted. When I run the following, I get back 1 , as expected.

(define-syntax-parser expand
    ((_) (datum->syntax this-syntax (format-datum '~a "(define (f x) x)"))))
(expand)
(f 1)

But if I try to hold the string in a variable source , I get back source: undefined; cannot reference an identifier before its definition source: undefined; cannot reference an identifier before its definition . I understand this is because macros are expanded at compile-time, when source has yet to be defined. Does anyone else have any ideas for how I might achieve this?

If you want to evaluate a string, then naïvely you want read and eval . You certainly don't want a macro.

Note this is insanely dangerous and almost certainly an extremely bad idea : running uncontrolled code (or even calling read unless you have absolute faith in read 's safety) that you have been sent by something only makes sense if you have implicit, total trust in the thing that sent you the code. There have been very many famous problems because people abused such trust. At the very least you should read Reflection and Security in the Racket documentation: especially the stuff on sandboxes. But sandboxed evaluators have also been subject to many famous exploits.

;;; May explode if exposed to light.  Hypergolic in air.
;;;

(define string-to-evaluate "
(define-syntax-rule (bind [v val] form ...)
  (let ([v val]) form ...))
(bind (foo 1)
  (+ foo foo))
(define bar 1)
")

(define (evaluate-string s (n (make-base-namespace)))
  (values
   (call-with-input-string
    s
    (λ (p)
      (for/list ([form (in-port read p)])
        (eval form n))))
   n))
> (evaluate-string string-to-evaluate)
'(#<void> 2 #<void>)
#<namespace>
> bar
bar: undefined;
 cannot reference an identifier before its definition
> (evaluate-string string-to-evaluate (current-namespace))
'(#<void> 2 #<void>)
#<namespace:'anonymous-module>
> bar
1 

But

> (evaluate-string "(require racket/system) (system \"echo now I own your computer\")")
now I own your computer
'(#<void> #t)
#<namespace>

Oops.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM