I am sure this has been done before in other languages, and is not an original idea. Nor do I know if anyone has proposed this idea before. At first I thought I might try to see if I could implement this myself, however, this is no small task. It could however be done in a way that is not as invasive as you would think but possibly at more of an expense to compilation times. We already suffer from long compilation times and making them longer is no a good way to get more people to use Rust so one must consider the ability to include this feature with out extending compilation times of crates that do not use this feature. So therefore in my idea of a design I use a method that could easily be programmed to not significantly effect compilation times.
I tried explaining this in two parts. The idea and the design, but that did not work out so just keep in mind the design of how it works does not have to be exactly like I say it is and the idea does not have to work exactly like I think it should.
Behold @syntaxfactory
. Ok, I’m done. No just kidding. Well, now you already basically know what it does just by looking at it. So let us see a more useful form of it.
Here, @syntaxfactory { fn foo_trybuild(AbstractSyntaxTree) { } }
. You see where I am going already I bet. You can likely figure out the entire idea from that. Of course I have a little more to my idea, but not much.
These things could be placed anywhere in any module in a crate. They might even inherit their enclosing scope but I think that might not work as well as it just sounds cool. Placing them anywhere would just help to locate the factory code closer to what it produces.
Now take the entire crate and filter all the files. Anything inside @syntaxfactory
's enclosing scope gets dropped into a new file with the same name and same directory structure as the containing module. So basically we kind of created two files with one file. We could essentially build a whole separate disk tree from our original disk tree entirely devoted to the syntax factory.
Let me introduce you to my friend the #[syntaxfactory(builder(foo)]
attribute. His job is to tag implementations (maybe more) that they have syntax factory capabilities. The capabilities are provided by Foo
. Now who is Foo
? Well, he might look like this: def foo_trybuild(?) -> ? { }
.
If you have not yet caught on to what will happen I will explain further. I will explain in the not optimized and just make it work method. Take all those @syntaxfactory
blocks drop them out into a new temporary hierarchy matching the original one such as a disk representation. You basically created a second crate. This crate is temporary in existence. The compiler then loads that crate dynamically into memory and uses the attributes and hooks to call out to the appropriate functions to modify the abstract/syntax/whatever tree pretty much like a macro does except more powerful.
Ok DONE. There you go. A long explanation for something that I could prolly have just referenced somewhere that is already implemented. But, I guess it kind of helped anyone who is not familiar with this idea. My friend a few weeks ago was telling me about another language that did something like that. I never checked that language out because I prefer to spend my time with Rust, but I did remember some of what he said and today I realized boy that would really be useful in a project of mine. So I envisioned a design that just might work hence my inability to completely separate the idea from the design.
Someone who has studied these type of things would be better equipped to actually design or determine the feasibility and usefulness of this idea, and someone with extensive knowledge of the compiler would be able to actually implement it. I might try at some point, but I am not very smart so I do not think I would get very far and then nobody would use it just like my other libraries, LOL.