csharplang
csharplang copied to clipboard
[Proposal] Ignored Directives Support
Ignored Directives
- [x] Proposed
- [ ] Prototype: Complete
- [ ] Implementation: In Progress
- [ ] Specification: Not Started
Summary
As we move to allow C# statements in the top level of a file, it's reasonable to assume that we might someday get support for dotnet run
ing a .cs file. For further use of C# as a scripting language in this vein, I propose that we introduce a new preprocessor directive who's purpose is to exist solely to be ignored by the language: the hashbang directive. Linux and Unix scripts will often use #!<path to interpreter>
in order to direct the program loader to the interpreter that can run them. We should add a similar ignore to the C# language.
Detailed design
We introduce a new directive:
pp_directive
: ... // Existing directives
| pp_hashbang
| pp_reference
;
pp_hashbang
: whitespace? '#' '!' input_character*
;
pp_reference
: whitespace? '#' 'r' whitespace input_character*
;
The language ignores the contents of the hashbang and reference directives and moves to the next line.
Drawbacks
Any change adds complication to the language. If we implement support for this and it starts appearing in files without actual scripting support, then it could be confusing for users expecting it to work.
Alternatives
N/A
Unresolved questions
- If we use these directives to support tooling such as nuget references, we will need to consider how they interact with other pragmas, such as
#if
. We have a few options for this:- Require that ignored directives are the first directives in a file. We could even go further and require they're all at the beginning of the file.
- Less restrictive than 1, but forbid ignored directives inside conditional directives.
- Least restrictive, require a true preprocessing step in the compiler. Today, we can process directives up front without having to do a full multi-step preprocessing pass before lexing, but if we want to support nuget directives inside conditional directives we may need the full two-step process.
Design meetings
- https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-05-12.md#simple-c-programs
- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-08-31.md#ignored-directives-support
- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-09-26.md#ungrouped
I'm worried about BOM. The presence of the BOM before the shebang will prevent the script interpreter.
Visual Studio for Win uses Encoding.Default (usually not UTF8) if the BOM doesn't present.
Sure, and we could certainly consider warning if the file uses anything other than UTF-8 w/o BOM.
I thought shebang was already supported... is it only in the .csx variant?
ah, looks like its only currently supported in the scripting mode.
https://github.com/dotnet/roslyn/blob/1b266a1e67434578ec09737a4e9427e52f44a420/src/Compilers/CSharp/Portable/Parser/DirectiveParser.cs#L108-L111
- As @yaakov-h mentions, shebang is already supported in the scripting dialect. Is this effectively formalizing that support and making it work in both dialects?
- If I understand it correctly, the shebang that's supported by the scripting mode has to be literally the first thing in the file: no whitespace before it, no other lines before it. Since that's the only way shebang works, does it make sense to support whitespace before it and to support it on lines other than the first line in the file?
I'm a little confused. Do "simple programs" not require a project file? How would a single file "script" in this manner establish references or change any compiler properties?
This feels like trying to bridge a gap between C# "simple programs" and CSX, which already has this support plus the directive support to make it actually useful. Short of adding that directive support this feels extremely limited.
Again, C# would benefit so much more from embracing CSX and improving the tooling support than it ever will by chasing CSX through some separate dialect that will always be much less capable.
I agree with @HaloFour without directives for assembly imports this might not be very useful. On the other hand having a script that downloads nuget packages or loading complex and somewhat big assemblies doesn't feel right for scripting.
The only thing that I kind of see as a big plus is that you can just take the cs file to any machine architecture and call dotnet run
on it so you don't have to compile aot.
What is still unclear for me is if the purpose of this proposal is that the cs-file is being interpreted or is it going to be compiled on running it.
If the purpose is to "just" interpreted on run, than I agree even more with @HaloFour we should focus on making csx a better experience.
I don't think it should introduce a new #!
directive to C#, for C# doesn't use #
for comment syntax.
How about:
/// <interpreter path="" />
Which will allow more complex definition, for example:
/// <project target="net5.0">
/// <properties>
/// <nullable>enable</nullable>
/// </properties>
/// <items>
/// <package include="Newtonsoft.Json" version="12.0.3" />
/// </items>
/// </project>
The point is to use a syntax that existing shells already recognize, otherwise there would be no benefit. Unix shells recognize shebang syntax and it is widely used to enable a script file to instruct the shell in how that file is to be interpreted. No shell will understand a C# comment or a blob of XML.
On Thu, May 28, 2020, 10:31 PM Steve [email protected] wrote:
How about:
///
I don't think it should introduce a new #! directive to C#, for C# doesn't use # for comment syntax.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dotnet/csharplang/issues/3507#issuecomment-635720859, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACNCMEWBCWZ6OAC346MHQHTRT4M6VANCNFSM4NMYL2BQ .
I summarize my understanding of this proposal at followings. Is it right?
-
C# compiler will simply ignore a shebang in the first line of the source. Because the lines start with
#
are preprocessor directives even on conventional spec, this modification looks not to impact other features. -
You can write inline csproj XML on and after 2nd line, but the interpretation of them should be done by build tool (e.g. dotnet-cli), not compiler. Such an inline csproj will be written under the conventional comment syntax, and the extension spec will be defined by tools.
#!/bin/dotnet run
//+ <Project Sdk="Microsoft.NET.Sdk">
//+ <PropertyGroup>
//+ <TargetFramework>netcoreapp3.1</TargetFramework>
//+ </PropertyGroup>
//+ </Project>
/*
* In this example, it is assumed that dotnet-cli will interprets the comments start with `//+` as inline csproj
*/
using System;
Console.WriteLine("Hello, world!");
The first point is correct, and is the only thing this proposal covers. This proposal makes no statement on how a program would communicate dependencies to a tool.