On Sun, Sep 4, 2022 at 4:21 AM Reuben Thomas <r...@sc3d.org> wrote: > > On Sat, 3 Sept 2022 at 19:10, Shu-Hung You <shh...@u.northwestern.edu> wrote: >> >> Running `racket foo.asm` will produce the desired output, so a shell >> script that directly passes the arguments to Racket could work. >> Otherwise, just use (dynamic-require filename #f) in main.rkt. > > > Thanks for helping! > > Don't both of these methods require a #lang line in the input file? That's > not part of the assembly format, so I want to be able to specify the language > in the main module. Indeed, when I try it with a file with a #lang line, > dynamic-require works; when I remove that line, I get an error about a > missing module declaration (no surprise). I can see an obvious workaround, > namely to slurp the file and prepend a module declaration before > dynamic-requiring it, but that's ugly. > > So it seems that in fact what I want is to call something like > dynamic-require with a module object. But I'm not sure what to call or how to > get one of those: read-syntax returns a syntax object, not a module, while I > don't (yet) know how to apply my expander's #%module-begin to it to obtain a > module. >
Okay, if you want to bypass the #lang protocol entirely, here is the needed code. As you have expected, it uses eval and then calls dynamic-require. diff --git a/asm.rkt b/asm.rkt index f2f1e89..4d024d8 100644 --- a/asm.rkt +++ b/asm.rkt @@ -6,6 +6,7 @@ (define (read-syntax path port) (define parse-tree (parse path (make-tokenizer port path))) - (strip-bindings - #`(module hackasm-mod hackasm/expander - #,parse-tree))) + (datum->syntax + #f + `(,#'module hackasm-mod hackasm/expander + ,parse-tree))) diff --git a/main.rkt b/main.rkt index 9f2af0b..9cccf22 100644 --- a/main.rkt +++ b/main.rkt @@ -8,4 +8,6 @@ #:program "hackasm" ; FIXME: get name from project #:args (filename) filename))) - (dynamic-require filename #f))) \ No newline at end of file + (parameterize ([current-namespace (make-base-empty-namespace)]) + (eval (read-syntax filename (open-input-file filename))) + (dynamic-require '(quote hackasm-mod) #f)))) There are two technical details. The eval function takes pretty much everything --- plain values, syntax objects, or just S-expressions, etc. For eval, the difference between syntax objects and S-expressions is that syntax objects carry binding information with them, therefore eval can correctly run the code without the risk of misinterpreting identifiers. The syntax object that your read-syntax returns is almost runnable, so I use eval to evaluate the resulting module form (i.e. #'(module hackasm-mod hackasm/expander ...)). This will declare a module called ‘hackasm-mod’ together with its code in the current namespace's module registry. Subsequently, dynamic-require instantiates the module ‘hackasm-mod’ to run its body. The reference https://docs.racket-lang.org/reference/module.html#%28form._%28%28quote._~23~25kernel%29._module%29%29 specifies what evaluating a module form results in (search for "evaluation"). In dynamic-require, the module path (quote hackasm-mod) refers to the module declared with the name ‘hackasm-mod’. In the more common cases, module paths would be complete file paths. The page https://docs.racket-lang.org/guide/module-paths.html explains the syntax of module paths. In the original read-syntax, I suppose strip-bindings removes all binding information associated with the given syntax objects. Consequently, eval would fail to interpret the resulting module form because the "module" identifier in it is unbound and thus has no meaning. To fix the issue, I explicitly use the #'module identifier found in asm.rkt (which is the Racket binding of ‘module’, brought into context by #lang br/quicklang). Then datum->syntax turns the entire list into a syntax object with no binding information. Equivalently, instead of changing read-syntax you can manually fix the #'module identifier before `eval` using the low-level APIs syntax-e and datum->syntax. >> At the technical level, foo.asm is in fact an ordinary Racket module, >> just like any other .rkt file. Therefore it can be run in the same way >> using APIs that require and instantiate modules. > > > Right! That's what I've obviously not fully understood yet. > > (Thanks for the side node about moving to Discourse—it's a while since I've > been active on the list!) > > -- > https://rrt.sc3d.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/CAMTzy%2BavnPCDvR8wHN3O_9BgnpQK%2BtamD9PqmBwd%2B9j-YGHUqg%40mail.gmail.com.