Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for $/require string literals of relative racketscript modules #278

Open
kurinoku opened this issue Dec 8, 2021 · 9 comments
Labels

Comments

@kurinoku
Copy link

kurinoku commented Dec 8, 2021

Right now the intents seems to just use $/require for javascript modules wether installed or relative, but support could be added to catch literals ending in .rkt, replace their extension to .rkt.js and add them to the dependency tree.

@stchang
Copy link
Member

stchang commented Dec 8, 2021

Anything in the interop library (with a $ prefix) is equivalent to directly writing plain js. It shouldnt know anything about Racket.

So if something like this were to be added, it should be a new form I think, rather than a change to $/require.

But in this case, is there a reason why the .rkt.js file could not be directly imported? (Is the use case to improve compile time?)

@kurinoku
Copy link
Author

kurinoku commented Dec 8, 2021

You are right that since it's part of the ffi it shouldn't know about Racket, but I think there should be then some form/procedure to tell the compiler to load certain modules.

My use case it has to do with this, evobot handling of command loading, it loads all the commands in a file, so one does not have to reference each one of the names.

const commandFiles = readdirSync(join(__dirname, "commands")).filter((file) => file.endsWith(".js"));
for (const file of commandFiles) {
  const command = require(join(__dirname, "commands", `${file}`));
  client.commands.set(command.name, command);
}

I got this

#lang racketscript/base
(require (for-syntax racket/base
                     racket/syntax
                     racket/path
                     syntax/parse))

(define-syntax (require+save-commands stx)
  (syntax-parse stx
    [(_ path:string save-to:id)
     #:with name-bind (format-id this-syntax "command")
     (let ([base-src (syntax-source #'path)]
           [path/string (syntax-e #'path)])
       (let-values ([(base _name _dir?) (split-path base-src)])
         (with-syntax*
             ([(mod-paths ...)
               (for/list ([p (in-list (directory-list (build-path base path/string)))]
                          #:when (path-has-extension? p #".rkt"))
                 (path->string (build-path path/string p)))]
              [(tmp ...) (generate-temporaries #'(mod-paths ...))])
           #'(begin
               (require (only-in mod-paths [name-bind tmp]) ...)
               (provide save-to)
               (define save-to
                 ($/array tmp ...))))))]))

(require+save-commands "commands" commands)

And it works perfectly fine, I was just wondering if a more straighforward way of doing this was worth implementing.
For example

(define-syntax (require+save-commands stx)
  (syntax-parse stx
    [(_ path:string save-to:id)
     #:with (mod-paths ...) (for/list ([p (in-list (directory-list (syntax-e #'path)))] 
                                                    #:when (path-has-extension? p #".rkt"))
                                          (path->string p))
     #'(begin
           (provide save-to)
           (define save-to
             ($/array ($/require mod-paths) ...)))]))

require+save-commands "commands" commands)

Now, I realize now that I know a bit more of racketscript and nodejs with ES modules, that this might just not work at all (because the require function is not used in ES modules and if I recall correctly $/require is for the syntax require not the function).

I still think an easy way to do the same should be provided, but I realize that it may be outside the scope of the project.

@stchang
Copy link
Member

stchang commented Dec 8, 2021

$/require should correspond to nodejs require function, so it should be possible to write that js code snippet directly using the ffi.

But is the issue that the files in the directory will now be racket files so they would need to be compiled first?

@kurinoku
Copy link
Author

kurinoku commented Dec 8, 2021

Yes, that would be the issue, since the compiler does not consider usages of $/require with racket files to be a dependency that has to compile.

@stchang
Copy link
Member

stchang commented Dec 16, 2021

I would support adding something like $/require/rkt, but could you fill in some more use case details? I still have a disconnect between the js use case and what the analogous racket would look like.

From what I understand, the result of calling (require "command.js") in js is an exports object that gets explicitly constructed in command.js?

So if I call ($/require/rkt "commands.rkt"), what does commands.rkt look like? Is there an explicit exports object? Or is exports generated as part of the call/compilation (and gets implicitly populated with all the provides)? Or something else?

@kurinoku
Copy link
Author

I would implement it as just a compilation hook that add the dependency of that file into the process, and it just translates in javascript to require("<name-of-file>.js").

@stchang
Copy link
Member

stchang commented Dec 16, 2021

Ok that's pretty straightforward then

stchang added a commit to stchang/racketscript that referenced this issue Dec 17, 2021
@stchang
Copy link
Member

stchang commented Dec 17, 2021

I tried to add the requested $/require/rkt, see #286

But I think I'm running into the problem I alluded to above, which is that the required library doesn't have the expected exports?

The specific error I'm getting is SyntaxError: The requested module './rktlib.rkt.js' does not provide an export named 'default'

@kurinoku If you have a chance, could you try out that branch and see if it does what you want? If not feel free to modify

@vishesh
Copy link
Member

vishesh commented Dec 17, 2021

Seems like its doing something like import default from mod.js which is probably not right?

@stchang stchang added the ffi label Apr 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants