Meaningful identifiers and other multi-token keywords

Quirin Schroll qs.il.paperinik at gmail.com
Thu Sep 26 21:05:31 UTC 2024


On Wednesday, 25 September 2024 at 15:50:20 UTC, Tim wrote:
> On Tuesday, 24 September 2024 at 20:37:36 UTC, Quirin Schroll 
> wrote:
>> I want to suggest moving the parsing of scope guards and 
>> linkages to the lexer, i.e., if the lexer sees `scope`, `(`, 
>> any one of the identifiers `exit`, `success`, or `failure`, 
>> and `)`, that is a scope guard and is treated as a single 
>> token.
>>
>> The same with `extern(C)` – it will never be seen as anything 
>> but a linkage. It’s a multi-token keyword.
>
> I don't think, the lexer would be the right place, because the 
> constructs are still multiple tokens. For example whitespace 
> and comments are allowed in `extern  (  C  ++ /*comment*/ )`.

The whitespace is not an issue. The comments maybe are. But even 
if they were, one option would be to just ban comments in linkage 
attributes and scope guards and not deal with the problem. I 
mean, who would do that, except for a QA tester?

> Unknown languages in `extern(...)` attributes should also 
> produce errors, so future compilers can add them without 
> breaking code.

Officially, it’s implementation defined what’s supported beyond 
`D` and `C`, see 
[here](https://dlang.org/spec/attribute.html#LinkageAttribute). 
The fact that DMD supports `C++`, `Objective-C`, `System`, and 
`Windows` is already an extension.

Considering C++ namespaces, the syntax is quite flexible. 
Essentially, any token soup with balanced parentheses is allowed. 
Maybe C++ was right, there it’s `extern "C"`.

> Consider this example:
> ```
> extern(X) x = 0;
> ````
> Currently `X` is a normal identifier, but in the future it be 
> could another language supported by the compiler. If `(X)` is 
> interpreted as a type, then adding `extern(X)` to the compiler 
> would be a breaking change. For forward compatibility it would 
> be best if `extern(...)` and `scope(...)` are always parsed as 
> whole attributes and not attributes with types in parens. 
> Unknown languages or scope guard identifiers would then produce 
> errors, so future compilers could add them without breaking 
> code.

With Primary Type Syntax, `extern (Type)` can happen by accident, 
yes.

Then, `Type` could happen to be a valid linkage, but even in that 
case, there’s a high likelihood that there’s a parse error down 
the line. (I fact, it might be guaranteed, I couldn’t find a way 
how it’s not.) That is because linkage attributes are not storage 
classes. Unlike `static`, `ref`, etc., `extern(C)` cannot be used 
instead of `auto`.

```d
// Current behavior:
alias C = int;

extern (C) x = 0; // Error: basic type expected
extern (C) auto x = 0; // Good, and `C` can’t be the type of `x`

static extern (C) x = 0; // Error: basic type expected
extern (C) static x = 0; // Good, and `C` can’t be the type of 
`x`, even if it denotes a type

alias Type = int;

extern (Type) x = 0; // Error: Type is not a linkage
extern (Type) auto x = 0; // Error: Type is not a linkage

static extern (Type) x = 0; // Error: Type is not a linkage
extern (Type) static x = 0; // Error: Type is not a linkage

// My implementation:
alias C = int;

extern (C) x = 0; // Error: basic type expected
extern (C) auto x = 0; // Good, and `C` can’t be the type of `x`

static extern (C) x = 0; // Error: basic type expected
extern (C) static x = 0; // Good, but `C` can’t be the type of 
`x`, even if it denotes a type

alias Type = int;

extern (Type) x = 0; // Error: `Type` is not a linkage
extern (Type) auto x = 0; // Error: `Type` is not a linkage

static extern (Type) x = 0; // Error: `Type` is not a linkage
extern (Type) static x = 0; // Error: `Type` is not a linkage
```

 From what I’ve understood in [the attribute 
spec](https://dlang.org/spec/attribute.html), `extern` marks a 
symbol a declaration whereas without, it would be a definition. 
It comes with or implies `export`, or at least implies `static`. 
So, if needed, one can just put that (or any nothingburger) 
between `extern` and `(Type)` and be good.

```d
// My implementation
extern export (Type) x; // ok
extern static (Type) y; // ok
extern @0 (Type) z; // ok
```


More information about the Digitalmars-d mailing list