-
Notifications
You must be signed in to change notification settings - Fork 0
Description
When I see some of the topics here and elsewhere about building languages for rust, most of it become talks about performance, deals with quirks of platforms, GC, and other matters that could obscure how actually implement a language. For some users, all that details become a wall that communicate "this is not for you". Yet, a simple language can be done in a few hours.
Also, what is best for an author/lang is not for other. Ones need fast JIT compilers, others transpilers, others fast parse -> execute loops, others are just exploring and researching, etc. This mean that even things like LLVM are hardly usefull for a lot of cases.
Under the https://nanopass.org idea, go to ast -> ?? -> execute can be changed at will. So, instead of a coupling like:
parsing -> AST -> execute
//Change minds, rewrite a lot:
parsing -> AST -> gen bytecode -> parsing bytecode -> execute
Everything is "just" chain another pass:
steps = [parsing, AST, execute]
steps.iter....
//Change minds, just add more specialization
steps = [parsing, AST, [gen bytecode, parsing bytecode ], execute]
This mean the under the nanopass style, the authors define/build "a pass" and the framework is only concerned in how combine and transform them. This allow for a lot of flexibility (ie: You can swap the "generate bytecode" for "format the code like rust-fmt" and still retain part of the effor (lexer, build ast).
So the idea is have something like:
trait CompilerPass {...}
impl CompilerPass for Lexer {}
impl CompilerPass <Lexer> for LossLessAST {}
impl CompilerPass <LossLessAST> for SugaredAST {}Other places where this style show:
This is at least on production with Chez scheme:
https://news.ycombinator.com/item?id=15156027
I think the case of middlewares show clearly the benefits:
#[actix_rt::main]
async fn main() {
let app = App::new()
.wrap_fn(|req, srv| { <-- Inject freely. Easy introspection and quick debugging
println!("Hi from start. You requested: {}", req.path());
srv.call(req).map(|res| {
println!("Hi from response");
res
})
})
.wrap(Logger::default()) <-- Common middlewares allow to reuse efforts across the community
.wrap(
CookieSession::signed(&[0; 32])
.secure(false),
) <-- Inject state and thread across the pipeline (for example, debugging info)
...<--And finally, add/remove at will. Not pay for what you don't need.
.route(
"/index.html",
web::get().to(|| async {
"Hello, middleware!"
}),
);
}Originally posted by @mamcx in #1 (comment)