Skip to content
← Back

src/semantic/dotnet/assembly_info.ghul

1
namespace Semantic.DotNet is
2
use Collections
3
4
use TYPE = System.Type
5
6
// Attributes applied to the assembly itself, each requested as the
7
// attribute's full name and a string value. A request is matched to a
8
// public constructor of the attribute taking only strings before
9
// anything is emitted: one taking a single string is given the whole
10
// value, and failing that one taking two is given the value split at
11
// its first comma, which is how an attribute such as
12
// AssemblyMetadataAttribute is given a key and a value.
13
class ASSEMBLY_INFO(_context: IR.CONTEXT) is
14
_requested: LIST[(name: string, value: string)]
15
_resolved: LIST[(name: string, assembly_name: string, arguments: List[string])]
16
17
UNMATCHED: string static => "assembly-attribute-unmatched"
18
19
init(..) is
20
_requested = LIST[(name: string, value: string)]()
21
_resolved = LIST[(name: string, assembly_name: string, arguments: List[string])]()
22
si
23
24
add_attribute(name: string, value: string) is
25
_requested.add((name = name, value = value))
26
si
27
28
// Matches every requested attribute to a constructor, returning a
29
// message for each that cannot be. Only the matched ones are
30
// emitted, so nothing refers to a constructor that does not exist,
31
// and an unmatched one is left out of the assembly.
32
resolve(find_type: (string) -> TYPE?) -> List[string] is
33
let problems = LIST[string]()
34
35
_resolved.clear()
36
37
// Found the same way as the attributes, so that it is the string
38
// type their constructors are declared with: a type loaded for
39
// inspection is not the running process's own.
40
let string_type = find_type("System.String")
41
42
for request in _requested do
43
let type = find_type(request.name)
44
45
if !type? then
46
problems.add("assembly attribute {request.name} not found")
47
48
continue
49
fi
50
51
let arguments =
52
if let text = string_type then
53
arguments_for(string_constructor_arities(type, text), request.value)
54
else
55
null
56
fi
57
58
if let matched = arguments then
59
_resolved.add((
60
name = request.name,
61
assembly_name = type.assembly.get_name().name ?? "System.Runtime",
62
arguments = matched
63
))
64
else
65
problems.add(
66
"assembly attribute {request.name} has no constructor taking "
67
"{if request.value.contains(',') then "one or two strings" else "one string" fi}"
68
)
69
fi
70
od
71
72
return problems
73
si
74
75
// How many strings each public constructor taking nothing but
76
// strings takes.
77
string_constructor_arities(type: TYPE, string_type: TYPE) -> LIST[int] static is
78
let result = LIST[int]()
79
80
for constructor in type.get_constructors() do
81
let parameters = constructor.get_parameters()
82
let all_strings mut = true
83
84
for parameter in parameters do
85
if parameter.parameter_type != string_type then
86
all_strings = false
87
fi
88
od
89
90
if all_strings then
91
result.add(parameters.count)
92
fi
93
od
94
95
return result
96
si
97
98
// The constructor arguments a value supplies, given the arities of
99
// the string-only constructors on offer, or null if none fits.
100
arguments_for(arities: LIST[int], value: string) -> List[string]? static is
101
if arities.contains(1) then
102
let whole = LIST[string]()
103
104
whole.add(value)
105
106
return whole
107
fi
108
109
let comma = value.index_of(',')
110
111
if arities.contains(2) /\ comma >= 0 then
112
let pair = LIST[string]()
113
114
pair.add(value.substring(0, comma).trim())
115
pair.add(value.substring(comma + 1).trim())
116
117
return pair
118
fi
119
120
return null
121
si
122
123
gen(emitter: IR.Emitter.SRM_ASSEMBLY_EMITTER) is
124
for attribute in _resolved do
125
let argument_types = LIST[Types.Type]()
126
127
for _ in attribute.arguments do
128
argument_types.add(IoC.CONTAINER.instance.innate_symbol_lookup.get_string_type())
129
od
130
131
emitter.add_named_attribute(
132
emitter.assembly_handle,
133
attribute.assembly_name,
134
attribute.name,
135
argument_types,
136
IR.Emitter.SRM_ATTRIBUTE_BLOB_ENCODER.encode_string_arguments(attribute.arguments))
137
od
138
si
139
si
140
si