Skip to content
← Back

src/semantic/symbols/indexer_names.ghul

1
namespace Semantic.Symbols is
2
// The names an indexer's accessors are declared under.
3
//
4
// .NET does not fix them: the indexer property carries whatever
5
// name its declaring language chose (`System.String`'s is `Chars`,
6
// C#'s default is `Item`, `IndexerName` overrides it), and the
7
// declaring type names the real one with
8
// `System.Reflection.DefaultMemberAttribute`. A type can also carry
9
// indexed properties that are not that one.
10
//
11
// So an imported indexer is declared under these names whatever it
12
// is called in metadata, and keeps its own name for emission via
13
// `il_name_override`. Everything that resolves an `x[i]` expression
14
// then has a single pair of names to look for, whether the type
15
// came from source or from an assembly.
16
class INDEXER_NAMES is
17
// The property name a source indexer takes, and what the
18
// default member is called on all but a handful of imported
19
// types.
20
//
21
// Named in snake_case rather than as UPPER_SNAKE constants
22
// because a static member's name is de-camelled when the
23
// assembly is read back through reflection, so an UPPER_SNAKE
24
// one is spelled differently either side of an assembly
25
// boundary — `READ` here and `read` from the unit tests.
26
property_name: string static => "Item"
27
28
read: string static => "get_{property_name}"
29
assign: string static => "set_{property_name}"
30
31
// The name to declare an accessor of `property_name` under:
32
// an indexer accessor is renamed, any other accessor keeps
33
// the name it came in with.
34
accessor(dotnet_name: string) -> string static =>
35
if dotnet_name.starts_with("set_") then
36
assign
37
else
38
read
39
fi
40
41
// True when metadata already names the accessor the way it is
42
// declared, so no second name is needed to reach it.
43
is_canonical(dotnet_name: string) -> bool static =>
44
dotnet_name =~ read \/ dotnet_name =~ assign
45
si
46
si