Matthew,

> You have a reader for your language that is triggered by "#lang",
right?

Is that reader in a `reader` submodule, or is it in a separate
".../lang/reader.rkt" module file?

In a separate file:

$ cat lang/reader.rkt
(module reader syntax/module-reader
  #:language 'slon/slon-language
  #:read slon-read
  #:read-syntax slon-read-syntax
  #:whole-body-readers? #t
  #:language-info '#(slon/lang/lang-info get-info #f)
  #:info (lambda (key defval default)
           (case key
             ((color-lexer)
              (dynamic-require 'slon/tool/syntax-color 'get-syntax-token))
             (else (default key defval))))
  (require slon/slon-parser))


I believe I used that approach before submodules appeared
in Racket... why does it matter anyway?

Regards,

Dmitry




At Fri, 13 Sep 2013 17:01:36 +0400, Dmitry Pavlov wrote:
Matthew,

Many thanks! Your code works perfectly for my program.

Now I would like to describe my tries to make a standalone
executable out of my program.

Most obvious way fails:

$ raco exe slon-main.rkt
$ ./slon-main
standard-module-name-resolver: collection not found
    collection: "slon"
    in collection directories:
    context...:
     standard-module-name-resolver

Not surprising, as the "slon" collection is not mentioned
in the slon-main.rkt itself, but is required dynamically.

So my second thought was that maybe ++lib would help.
It did not. (Did I use the flag incorrectly?)

$ raco exe ++lib slon/slon-language slon-main.rkt
$ ./slon-main
<same error message>


Seeking for the solution, I upgraded from raco to the Racket level:

#lang racket
(require compiler/embed)

(create-embedding-executable "slon-main"
       #:modules '((#f slon/slon-main) (#f slon/slon-language))
       #:literal-expression
         (parameterize ([current-namespace (make-base-namespace)])
                 (compile `(namespace-require 'slon/slon-main)))
       #:configure-via-first-module? #t
       #:verbose? #t)

That worked great. "slon-main" was able to run independently
of its own location in the file system, and indenendeltly
of the presence of the original files in the slon/ collection
on disk.

But there was another thing. In my implementation, I have
some binary data files that are loaded via

(define-runtime-path eop.era "../eop/eop.era")

The resulting program depended on those files. When I renamed
one of them, I got an error message:

$ ./slon-main
with-input-from-file: cannot open input file
    path: /home/dpavlov/era/slon/../eop/eop.era


"OK", I thought, "raco distribute is supposed to fix that".


$ raco distribute slon-distr slon-main
$ ls ./slon-distr/lib/plt/slon-main/exts/ert/home/dpavlov/era/eop/
eop.era
$ ./slon-distr/bin/slon-main
standard-module-name-resolver: collection not found
    collection: "slon"
    in collection directories:
     /home/dpavlov/.racket/5.3.4/collects
     /home/dpavlov/era/slon/slon-distr/lib/plt/slon-main/collects

The executable "slon-main" produced by raco distrubute is
different from the original one (although the size is the same).
I guess, raco distribute have eliminated the dependency of the
binary files with absolute paths, but it reintroduced the
dependency on the "slon" collection, which I previously got
rid of with the help of (create-embedding-executable)!

And here I am stuck, asking for help.


Regards,

Dmitry




On 09/13/2013 05:33 AM, Matthew Flatt wrote:
I'm not sure I understand what you want, but here are some ideas about
evaluating a text that would a module if only a "#lang" line were
added.

To start, here's a function to `require` an input port that contains a
module's source. It uses the current namespace, and it gensyms a name
for the module if you don't provide one. The part that I think is least
obvious is using `current-module-declare-name` to set the name of the
module to that it can be found by `dynamic-require`:

   (require syntax/modread)

   (define (require-input-port p [name (gensym)])
     (define module-name (make-resolved-module-path name))
     (parameterize ([current-module-declare-name module-name])
       (eval-syntax (check-module-form ; ensures that `module` is bound
                     (with-module-reading-parameterization
                      (lambda ()
                        (read-syntax (object-name p) p)))
                     'ignored
                     #f)))
     (dynamic-require module-name #f))

The `require-input-port` function assumes that the source starts with
"#lang". You could use `input-port-append`, as others have suggested,
to add a "#lang" line:

   (define p (input-port-append #t
                                (open-input-string "#lang racket/base\n")
                                (open-input-file "body.rktd")))
   (port-count-lines! p)
   (require-input-port p)

A problem with `input-port-append` is that line numbers are off by one
for error reporting, and positions are off by the length of the first
line. That's an annoyingly difficult problem to fix, but
`prefix-input-port` below is my attempt (and maybe `input-port-append`
should just work better along similar lines).

   (define p (prefix-input-port #"#lang racket/base\n"
                                (open-input-file "body.rktd")))
   (port-count-lines! p)
   (require-input-port p)

----------------------------------------

;; prefix-input-port : bytes input-port -> input-port
;;  Directs position requests to the given port after the
;;  prefix is read.
;;  Closes the given input port when the result port is closed.
(define (prefix-input-port prefix base-p)
    (define-values (prefix-i prefix-o) (make-pipe))
    (write-bytes prefix prefix-o)
    (close-output-port prefix-o)
    (define (prefix-done?)
      (zero? (pipe-content-length prefix-i)))

    (make-input-port
     (object-name base-p)
     ;; read
     (lambda (bstr)
       (define n (read-bytes-avail!* bstr
                                     (if (prefix-done?)
                                         base-p
                                         prefix-i)))
       (if (equal? n 0)
           (wrap-evt base-p (lambda (v) 0))
           n))
     ;; peek
     (lambda (bstr offset evt)
       (define pre-n (pipe-content-length prefix-i))
       (define n (if (offset . >= . pre-n)
                     (peek-bytes-avail!* bstr
                                         (- offset pre-n)
                                         #f
                                         base-p)
                     (peek-bytes-avail!* bstr
                                         offset
                                         #f
                                         prefix-i)))
       (if (equal? n 0)
           (wrap-evt base-p (lambda (v) 0))
           n))
     ;; close
     (lambda ()
       (close-input-port base-p))
     ;; get-progress-evt
     ;;  Difficult (impossible?) to support at the
     ;;  prefix--base boundary.
     #f
     ;; commit
     #f
     ;; get-location
     (lambda ()
       (if (prefix-done?)
           (port-next-location base-p)
           (port-next-location prefix-i)))
     ;; count-lines!
     (lambda ()
       (port-count-lines! prefix-i)
       (port-count-lines! base-p))))






____________________
 Racket Users list:
 http://lists.racket-lang.org/users

Reply via email to