Closed Columbus240 closed 1 month ago
For generated source I prefer solution like javascript sourcemap
I couldn't find such a thing for rust. There are tools like noerr, but I consider this an inadequate solution. Language support would be nice. In the reddit thread I linked to, there's the proposal of
#[line 10 grammar.y] // line 51 generated.rs
{ // line 52 generated.rs
foo(); // line 10 grammar.y
bar(); // line 11 grammar.y
baz(); // line 12 grammar.y
} // line 56 generated.rs
which I think is acceptable and should work with the rest of the language, as far as I know it.
I just thought of a problem of the above notation. It introduces new code blocks, where it would be nice not to have them. It would prohibit different chunks of accessing each others declarations. The process would have to be similar to C, that the line numbers simply increment, but there would have to be a command to reset, so the line numbers get counted in the actual file again.
What I mean:
#[line 10 grammar.y] // line 51 generated.rs
foo(); // line 10 grammar.y
bar(); // line 11 grammar.y
baz(); // line 12 grammar.y
#[line 32 grammar.y] // line 55 generated.rs
orange(); // line 32 grammar.y
#[line reset] // line 57 generated.rs
I know it would make Rust more complicated to read and compile because there is no language feature like it. This problem doesn't exist in C, because the preprocessor has its relevant place in the language. Because this code would almost never have to be read and written, except by the code generator and the compiler, readability is not much of a concern. But more complicated compiler code might be a problem, but I don't know the specifics.
A link to a discussion from February on the rust internals forum about this topic.
Some form of emitting line number information would be useful to re2rust
lexer generator from re2c
project: http://re2c.org/manual/manual_rust.html
I do a lot of codegen at times, and having a #[source_location(source_name: &str, line_num: u32, col_num: u32)]
attribute (type specifiers for doc purposes)--where line_num
and col_num
default to 1
if only one or two args are passed--would be amazingly useful.
See also: C/C++, C#, Java, Perl. But not: JS, LISPs, Lua, Make, Python. I've had to target Perl instead of JS, Lua, or Python for this reason, when any of those three would be more au courant, and thus more maintainable.
Similarly, today, I'll choose C++ over Rust for applications that would benefit from AOT compiled codegen, like embedded state machines, workflow engines, and codegenned clients and servers from, e.g. OpenAPI specs.
The issue with source maps is that there's a whole 'nother artifact / dataflow to keep in sync, and it means that all compile time and runtime error-reporting now have to support an additional input, including backcompat / forward compat as the format evolves, and the build and delivery chains--package managers, CI/CD, and the old "Desperate DevOps Hacker" copying things by hand--all have to bundle and keep them in sync with the source.
I’m not convinced that source maps would be a problematic solution. Instead of generating line directives, you would generate a source map and put it as an attribute somewhere in the file, e.g. #![source_map = "<source map data here>"]
at the very top or bottom. There would be no need for separate files to be maintained.
At the time I made this issue, I didn't think/know of source maps. Thanks for the idea.
Since I'm not interested in this problem anymore, I'll close this issue.
Currently rust isn't well suited for generated files, because when an error occurs, it will provide the position of the faulty line in the generated file and not in the actual source file. C solved this with its
#line
preprocessor directive, which allows the generating program to tell the compiler which part of the source file influenced the rust code. This is used, for example, in parser generators and literate programming tools.There have been some discussions about this: A reddit thread. A thread from the rust forums