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

Nested modules in definitions #64

Closed
tamasfe opened this issue Jul 24, 2022 · 17 comments
Closed

Nested modules in definitions #64

tamasfe opened this issue Jul 24, 2022 · 17 comments
Labels

Comments

@tamasfe
Copy link
Member

tamasfe commented Jul 24, 2022

Currently it's not possible to define nested modules in definition files.

Nested modules can only come from import statements.

The solution is simple-ish without breaking the existing architecture.

We can define arbitrary modules within a module with the following syntax:

// `foo` is the name of the root module
module foo;

fn some_function();

// `bar` is a submodule of `foo`
module bar {
  const baz: ?;
  fn some_inner_function();
}

And then we flatten the inner modules and assign unique URIs to them, then treat them as usual afterwards.

@schungx
Copy link
Collaborator

schungx commented Jul 24, 2022

I wonder what need to set the root module name is...

Since the user can do:

import "foo" as xyz;

xyz::some_function();

xyz:;bar::some_inner_function();

That would mean that the root name can be freely changed by the script.

Otherwise you'd need to force the user to always do module xyz; at the beginning of the definition file. In that case, however, you'd lose the ability to reuse/share the definition files.

Alternatively, you can keep some form of a mapping dynamically, mapping xyz to foo (the root name in the definitions file). Whenever you see xyz::..., you replace the root with the mapped root. Then Bob's your uncle!

@tamasfe
Copy link
Member Author

tamasfe commented Jul 24, 2022

These definitions are only for modules that are already loaded in the engine.

By using register_submodule("foo", some_module);, you will always end up with a definition file that starts with module foo;.

@schungx
Copy link
Collaborator

schungx commented Jul 24, 2022

Ah OK. I understand.

However, in the examples, I see import "./bar.rhai" as bar; which is importing a script file with a definition file...

I wonder what will happen if I change the import to import "./bar.rhai" as foo;? I'll try it out and see...

EDIT: Ha! It works just fine!

@tamasfe
Copy link
Member Author

tamasfe commented Jul 24, 2022

It should work as you expect, otherwise file a bug.

I made a distinction between modules that are already loaded, and modules introduced by import statements.

Using import "foo" as xyz; is the same as declaring xyz in the engine. The "foo" part only addresses how to load the module and has nothing to do with its name. Afaik you can do this in both script and definition files, and it should work just fine.

The module xyz; definition files are only needed for modules already registered in the engine, they could theoretically be rewritten as import "whatever" as xyz. The only issue is with nesting, as currently nesting is only possible via import statements.

You can define the following module structure in rust:

#[exported_module]
mod foo {
  mod bar {
    pub fn baz() {}
  }
}

The only way this can be expressed right now in definition files is the following:

module foo;

import "???" as bar;
/// bar
module "???";

fn baz();

This implies that bar can be imported from somewhere and re-exported from foo, which is not the case because it only ever exists under foo itself.

@schungx
Copy link
Collaborator

schungx commented Jul 24, 2022

As it looks like module definition files are likely going to be needed only for Rust-based modules, your solution of the module bar { ... } syntax to declare a sub-module should work fine.

@schungx
Copy link
Collaborator

schungx commented Jul 24, 2022

This only leaves one small issue of inconsistency...

Module definition files have their own syntax (sort of), and are used to document Rust-based functions and modules.

Rhai scripts will be parsed dynamically and documentation extracted from the scripts.

The inconsistency is that, in case that there is a definition file with the same name as a Rhai script, then the doc-comment on its top-most module statement will be taken as the documentation of that Rhai script file itself -- with all other information in the definition file ignored, I suppose.

I wonder if there is a way to embed module comments directly into the Rhai script itself to avoid you having to do this.

@tamasfe
Copy link
Member Author

tamasfe commented Jul 24, 2022

Can you give an example?

Definitions for scripts and existing modules should never conflict.

You can write the following for your script definition:

// foo.d.rhai
module "./foo.rhai";

fn whatever();
// foo.rhai

fn whatever () {}

Then a foo module from rust:

module foo;

fn whatever_from_rust();

The only way for these to conflict is doing

import "./foo.rhai" as foo;

At which point it's either a name conflict, or foo from rust is redeclared using the import from foo.rhai, I don't know how rhai handles these currently.

@schungx
Copy link
Collaborator

schungx commented Jul 24, 2022

I think I didn't make myself clear. What I mean is... a script file internally has all the documentation, and the only reason why we need a definition file is to provide documentation on the script file itself as a module.

Therefore, if I find a way to include module documentation inside the script file itself, then script files should never need definition files as they are self-contained. In that case, we keep all definition files exclusively for use with Rust modules.

At which point it's either a name conflict, or foo from rust is redeclared using the import from foo.rhai, I don't know how rhai handles these currently.

In this case, the import overrides the static namespace.

@tamasfe
Copy link
Member Author

tamasfe commented Jul 24, 2022

I see, yeah the syntax //! suggested earlier could help with this.

script files should never need definition files as they are self-contained

You currently need definitions for all type information, I think adding all of this to rhai should come after the definition format is fully tested and fleshed-out. I opened rhaiscript/rhai#488 for type hints, but I don't think it should be rushed as it'd be a significant addition.

@schungx
Copy link
Collaborator

schungx commented Jul 24, 2022

You currently need definitions for all type information,

Ah, got that. I see now. There is no way to get rid of definition files (unless I also embed type info into the script). Therefore, mind as well keep the current way of doing things then.

It is not simple to add a //! syntax and I would prefer to avoid introducing it unless it serves a really good purpose. That is because it theoretically can only occur at the beginning of a script file, but script files can be merged and joined from pieces. Therefore, it is very easy to get //! comments in the middle of a script.

@tamasfe
Copy link
Member Author

tamasfe commented Jul 24, 2022

Therefore, it is very easy to get //! comments in the middle of a script.

I don't think it's an issue, we can relax it to allow it anyhere and just merge them together, in fact we don't even need the support from Rhai in that case, and I can do it in the rowan-based parser alone.

@schungx
Copy link
Collaborator

schungx commented Jul 24, 2022

I don't think it's an issue, we can relax it to allow it anyhere and just merge them together, in fact we don't even need the support from Rhai in that case, and I can do it in the rowan-based parser alone.

That would be the best, I think. Do it in the LSP, and Rhai will continue to treat it as normal comments.

@schungx
Copy link
Collaborator

schungx commented Jul 24, 2022

In that case, the definition files for scripts will be to hold type declarations only. The script file's module doc can be obtained via //! blocks inside the script.

This looks like a great solution.

@schungx
Copy link
Collaborator

schungx commented Jul 24, 2022

I'll put //! on Rhai example scripts from now on, in anticipation to this feature.

@schungx
Copy link
Collaborator

schungx commented Jul 25, 2022

Inspired by your comment, I actually found an easy way to implement //! documentation in Rhai!

In the new version, AST::doc() would yield the script documentation.

@schungx
Copy link
Collaborator

schungx commented Jul 25, 2022

AST::doc() is available in the latest drop.

@tamasfe
Copy link
Member Author

tamasfe commented Jul 27, 2022

Solved in #69, and #70.

@tamasfe tamasfe closed this as completed Jul 27, 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

2 participants