I feel like I might not understand what you want, but it feels like
you just want to use `make-module-evaluator` from `racket/sandbox`:

```
#lang racket/base
(require racket/sandbox)

(define (read-script s)
  (((make-module-evaluator s) 'script) 5))

(module+ test
  (read-script
   "#lang racket/base
    (provide script)
    (define (script x) (add1 x))")
  (read-script
   "#lang typed/racket/base
    (provide script)
    (: script (-> Number Number))
    (define (script x) (add1 x))"))
```

You may want to set the `#:language` argument to control the language.
And you will also want to set `sandbox-namespace-specs` to link up
your internal data-structure providing modules so you can communicate.
But other than those two things, it should be pretty straightforward.
What is different about this than what you are trying to do?

Jay

--
Jay McCarthy
Associate Professor @ CS @ UMass Lowell
http://jeapostrophe.github.io
Vincit qui se vincit.

On Sun, Nov 10, 2019 at 7:15 PM Christopher Lemmer Webber
<cweb...@dustycloud.org> wrote:
>
> Hey Eric!  Thanks, I'll try to soak in this a bit tomorrow. :)
>
> Eric Griffis writes:
>
> > This works:
> >
> > 1. mkdir foo; cd foo; raco pkg install
> >
> > 2. create foo/main.rkt:
> >
> > ```
> > #lang racket/base
> >
> > (module reader racket/base
> >   (require racket/port)
> >   (provide (rename-out [foo-read read]
> >                        [foo-read-syntax read-syntax]))
> >   (define (foo-read port)
> >     `(module ,(gensym 'foo) racket/base
> >        (provide the-foo)
> >        (define the-foo (let () ,@(port->list read port)))))
> >   (define (foo-read-syntax path port)
> >     (datum->syntax #f (foo-read port))))
> > ```
> >
> > 3. In the REPL or another file, we can simulate the game's interaction with
> > the player's connection through an input port:
> >
> > ```
> > (define foo-source #<<END
> > #lang foo
> >
> > (define bar 1)
> >
> > (+ bar 2)
> > END
> >   )
> >
> > (define player-input (open-input-string foo-source))
> >
> > (define source
> >   (let ([define-mod (parameterize ([read-accept-reader #t])
> >                       (read player-input))])
> >     (define mod-name (cadr define-mod))
> >     `(begin ,define-mod (let () (local-require (quote ,mod-name))
> > the-foo))))
> >
> > (println `(GOT ,(eval source (module->namespace 'racket/base))))
> > ```
> >
> > The value-extraction code is kind of messy, so you might want to stow it in
> > a `port-read-handler`, like this:
> >
> > ```
> > (port-read-handler
> >  player-input
> >  (let ([default-handler (port-read-handler player-input)])
> >    (case-lambda
> >      [(in) (define original-handler (port-read-handler in))
> >            (define define-mod
> >              (parameterize ([read-accept-reader #t])
> >                (port-read-handler in default-handler)
> >                (begin0 (read in) (port-read-handler in original-handler))))
> >            (define mod-name `(quote ,(cadr define-mod)))
> >            (eval `(begin ,define-mod (let () (local-require ,mod-name)
> > the-foo))
> >                  (module->namespace 'racket/base))]
> >      [(in source) (datum->syntax #f (read in))])))
> >
> > (println `(GOT ,(read player-input)))
> > ```
> >
> > Eric
> >
> >
> >
> > On Sun, Nov 10, 2019 at 12:19 PM Christopher Lemmer Webber <
> > cweb...@dustycloud.org> wrote:
> >
> >> Hi Eric!  Thanks very much for the reply.
> >>
> >> Eric Griffis writes:
> >>
> >> >> It appears there must be; when I look at `build-program` in
> >> >> sandbox.rkt it also looks like it's wrapping things in a module
> >> >> structure... but I don't see how it then exports from that module or
> >> >> how the code evaluating it imports its export.  Or does it actually
> >> >> do so via an effect?  I see there are some channels involved
> >> >> (input-ch / result-ch) so maybe it's passing back the result through
> >> >> there, but I am having trouble figuring out how.
> >> >
> >> > Apologies for stating the obvious, but to get a value out of a module, we
> >> > `provide` it:
> >> >
> >> > In foo/main.rkt:
> >> >
> >> > ```
> >> > (define-syntax-rule (foo-module-begin form ... final-form)
> >> >   (#%module-begin (provide the-foo) form ... (define the-foo
> >> final-form)))
> >> > ```
> >> >
> >> > Then we can produce and consume foo-based modules like this:
> >> >
> >> > ```
> >> > (module bar-mod foo (define bar 1) (+ bar 2))
> >> >
> >> > (define my-bar (let () (local-require 'bar-mod) the-foo))
> >> > ```
> >>
> >> This approach works, but I'm not sure it works for my use case, because
> >> `module` is appearing at compile-time.
> >>
> >> Let me try to lay out the use case, and maybe it helps.
> >>
> >>  - We are in a MUD, or some other interactive game.  The game is running
> >>    live.  Some players have capabilities to provide new code for game
> >>    characters in the system or other interesting features.
> >>
> >>  - The users are able to write scripts that return things... however,
> >>    they are providing the scripts as the game is running.  (This will be
> >>    ocap safe, but I'll explains how that works in a separate
> >>    email... just trust me that I believe that if I can run it with in a
> >>    special restricted language and return a value from that module which
> >>    is loaded *at runtime* somehow, I can pull off this goal safely.)  As
> >>    such, we cannot at the time that we are starting the program actually
> >>    know or load all of the modules, because the users are providing some
> >>    of them live.
> >>
> >>  - As such we need to be able to do something along the lines of what
> >>    you just did, but we have to do it at runtime.
> >>
> >>  - I don't necessarily want to attach each of these user-supplied
> >>    modules to a global namespace; a user might experiment with making
> >>    many of them, and there's no need.
> >>
> >> Does that make sense?
> >>
> >> I'll explain more about how this can be ocap safe in a future email.
> >> For the moment, if you're curious on how this design works, more is
> >> here (the "emaker" pattern):
> >>
> >>   http://www.skyhunter.com/marcs/ewalnut.html#SEC16
> >>
>
> --
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-users/87r22fgteu.fsf%40dustycloud.org.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAJYbDa%3DET2ERves0LO%3DPi_zFkKGym_Z6urOhBnMhsqve4KPbOg%40mail.gmail.com.

Reply via email to