[racket] Evaluating pict to string

From: Eli Barzilay (eli at barzilay.org)
Date: Sun Apr 21 21:54:34 EDT 2013

20 minutes ago, manu d wrote:
> Hello
> 
> I am trying to port TryClojure
> (https://github.com/Raynes/tryclojure), a web-based REPL, to Racket.

Nice!  I wanted to look into that ages ago...  (There's a whole pile
of additional nice things that can be done with it.)


> I would like the tutorial part to be based on Racket's 'Quick'
> tutorial (http://docs.racket-lang.org/quick/)

Even better!


> To do that, I need to evaluate pict expressions, like (circle 10),
> to a string I can return to the browser for rendering.

Sidenote: to make things easy, it's probably best to use `data' URLs
-- things like:

  <img src="data:image/png;base64,--the-encoding-of-the-image--">



> Right now, I evaluate the strings coming from the browser with the
> following code:
> 
> ;;--------------------------------
> 
> (define evaluator
>     (parameterize ([sandbox-output 'string]
>                           [sandbox-error-output 'string] ...)
>       (call-with-limits #f #f

Another sidenote: this `call-with-limits' is completely useless...
This is because (a) there are no limits, (b) there's no need for
limits since the sandbox has that functionality baked it, (c) even if
there was a point, it wraps the sandbox creation rather than uses of
the resulting evaluator.


> [...]
> I know I can convert a pict structure like this: (convert a-pict
> 'png-bytes) but (evaluator "(circle 10)") does not evaluate to a
> pict structure, so I can't use convert here.

The problem is that the sandboxed world is completely separate from
your code's world.  You need to share some parts to make it possible
to treat resulting picts in the first as picts in the second.  This is
done with the `sandbox-namespace-specs' parameter.  Here's a small and
complete working example:

    #lang at-exp racket
    
    (require racket/sandbox file/convertible net/base64 scribble/html)
    
    (define specs ; add 'slideshow/pict to whatever is there
      (let ([old (sandbox-namespace-specs)])
        (cons (car old) (list* 'slideshow/pict (cdr old)))))
    
    (define e (parameterize ([sandbox-namespace-specs specs])
                (call-with-trusted-sandbox-configuration
                 (λ () (make-evaluator 'slideshow)))))
    
    (define (render-img expr)
      @img[src: (list "data:image/jpeg;base64,"
                      (base64-encode (convert (e expr) 'png-bytes)))])
    
    (define (eval-page expr)
      (output-xml
       @html{@head{@title{Evaluation result}}
             @body{@pre{> @expr
                        @render-img[expr]}}}))
    
    (eval-page "(circle 10)")

But like Robby said -- it's better to do the conversion inside the box
to avoid crashing the whole thing because someone just had to try
(circle 1000000).

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!


Posted on the users mailing list.