rust-lang / rfcs

RFCs for changes to Rust
https://rust-lang.github.io/rfcs/
Apache License 2.0
5.87k stars 1.56k forks source link

Add an attribute like C's `#line` #1862

Closed Columbus240 closed 1 month ago

Columbus240 commented 7 years ago

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

bungcip commented 7 years ago

For generated source I prefer solution like javascript sourcemap

Columbus240 commented 7 years ago

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.

Columbus240 commented 7 years ago

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.

Columbus240 commented 7 years ago

A link to a discussion from February on the rust internals forum about this topic.

trofi commented 1 year ago

Some form of emitting line number information would be useful to re2rust lexer generator from re2c project: http://re2c.org/manual/manual_rust.html

barries commented 1 month ago

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.

zopsicle commented 1 month ago

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.

Columbus240 commented 1 month ago

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.