Как сказать `make-module -valuator` использовать пользовательский ридер, как #lang? - PullRequest
3 голосов
/ 22 января 2020

Я пытаюсь выполнить пользовательский #lang для заданной строки (не в файле). Давайте назовем это broccoli.

Настройка

Мой язык определяется следующим образом:

broccoli / main.rkt

(module reader racket/base
  (require broccoli/private/reader)
  (provide read read-syntax)) ; basically a reprovide

брокколи / личное /reader.rkt

(provide
  (rename-out
    [my-read read]
    [my-read-syntax read-syntax]))

(define (my-read in)
  (syntax->datum
    (my-read-syntax #f in)))

(define (my-read-syntax src in)
  (with-syntax ([parse-tree (parse src (make-tokenizer in src))]) ; brag stuff
    (strip-context
      #'(module program broccoli/private/expander
          parse-tree))))

брокколи / частный / expander.rkt

(provide
  (rename-out [module-begin #%module-begin]))

(define-syntax-rule (module-begin expr)
  (#%module-begin
    (provide meal)
    (define meal (transform 'expr)))) ; some kind of computation

Работает довольно хорошо, если использовать класс c:

#lang broccoli
Hello world!

выдаст:

(module program broccoli/private/expander
  (program
    (sentence (word "Hello") (word "world"))))

, который затем расширится до:

(provide meal)
(define meal (list 42 38)) ; the result is for the sake of the example, don't mind it

Но я пытаюсь применить его к произвольной строке, полученной из сетевого запроса, и отправить обратно результат. И на этот раз все становится сложнее. Вот что я попробовал:

Попробуйте # 1

(define text "Hello world!")
(define evaluator (make-evaluator 'broccoli text)) ; Error: no #%module-begin found
(evaluator 'meal)

Попробуйте # 2

(define text "Hello world!")
(define module (broccoli-read-syntax #f (open-input-string text)))
(define evaluator (make-module-evaluator #:language 'broccoli/private/expander module))
(evaluator 'meal) ; Error: meal undefined

Попробуйте # 3

(define text "Hello world!")
(define evaluator (make-module-evaluator (string-append "#lang broccoli " text)))
(evaluator 'meal) ; Error: meal undefined

Попробуйте # 4 (это работает, но это не то, что я хочу)

(define text "Hello world!")
(define module (broccoli-read-syntax #f (open-input-string text)))
(define ns (make-base-namespace))
(eval module ns)
(namespace-require ''program ns)
(define result (eval 'meal ns))

Этот последний результат работает правильно, но он не использует песочницу и использует eval напрямую.
Я уверен, что есть лучше, но я не понимаю, что происходит не так.

Ответы [ 2 ]

2 голосов
/ 22 января 2020

Я был ооочень близок!

Мне пришлось запросить сгенерированный модуль внутри оценщика (что подразумевает предоставление #%app, #%top, #%top-interaction, require и quote от расширителя ).

(define evaluator (make-module-evaluator (string-append "#lang broccoli\n" text)))
(evaluator '(require 'program)) ; missing step
(evaluator 'meal)

Что я нахожу странным в этом решении, так это то, что оно не ведет себя так, как описано в документации:

> (define base-module-eval
    (make-module-evaluator '(module m racket/base
                              (define (f) later)
                              (define later 5))))
> (base-module-eval 'later)
5
1 голос
/ 22 января 2020

Я предлагаю использовать read-lang-module, чтобы превратить строку в объект синтаксиса, представляющий модуль. А затем используйте make-module-evaluator.

...