Skip to content
← Back

src/semantic/interpolated_value_rendering.ghul

1
namespace Semantic is
2
use Semantic.Types.Type
3
4
// How an interpolated value becomes text.
5
enum InterpolatedValueRendering is
6
// Formatted as .NET formats it: a string, a number, an enum, a
7
// type declaring its own to_string, or any value given a format
8
// or an alignment.
9
FORMATTED,
10
11
// `true` or `false`, as ghūl spells them.
12
BOOL,
13
14
// The value it holds, rendered by the rules for its non-optional
15
// type, or `null` when it holds none.
16
OPTIONAL,
17
18
// Rendered by the runtime's `$`: a value whose static type gives
19
// it no text of its own, which .NET would print as its type name.
20
DISPLAYED
21
si
22
23
class INTERPOLATED_VALUE_CLASSIFIER is
24
_lookup: Lookups.InnateSymbolLookup
25
26
init(lookup: Lookups.InnateSymbolLookup) is
27
_lookup = lookup
28
si
29
30
classify(type: Type, is_formatted: bool) -> InterpolatedValueRendering is
31
if is_formatted then
32
return InterpolatedValueRendering.FORMATTED
33
fi
34
35
if type.is_optional /\ type.optional_inner_type? then
36
return InterpolatedValueRendering.OPTIONAL
37
fi
38
39
if _is(type, _lookup.get_bool_type()) then
40
return InterpolatedValueRendering.BOOL
41
fi
42
43
// A function value has no text worth reading beyond its type,
44
// and rendering its delegate's members would expose the
45
// compiler's closure machinery.
46
if type.is_function \/ type.is_action then
47
return InterpolatedValueRendering.FORMATTED
48
fi
49
50
if
51
type.is_value_tuple \/
52
isa Types.TUPLE(type) \/
53
type.is_object \/
54
type.is_type_variable \/
55
type.is_classy_generic_argument \/
56
type.is_function_generic_argument
57
then
58
return InterpolatedValueRendering.DISPLAYED
59
fi
60
61
if _is(type, _lookup.get_string_type()) \/ has_own_to_string(type) then
62
return InterpolatedValueRendering.FORMATTED
63
fi
64
65
if isa Types.ARRAY(type) \/ type.is_trait \/ type.find_ancestor(_lookup.get_unspecialized_iterable_type())? then
66
return InterpolatedValueRendering.DISPLAYED
67
fi
68
69
// An imported type that says nothing of itself keeps its .NET
70
// type name: rendering it by its members would run whatever
71
// its property getters do.
72
if type.symbol.is_reflected then
73
return InterpolatedValueRendering.FORMATTED
74
fi
75
76
return InterpolatedValueRendering.DISPLAYED
77
si
78
79
// Whether a type says what it is in its own words, through a
80
// to_string declared somewhere other than the roots every type
81
// inherits one from. An enum counts: System.Enum's to_string gives
82
// the member's name.
83
has_own_to_string(type: Type) -> bool is
84
let to_string = zero_argument_to_string(type.find_member("to_string"))
85
86
if !to_string? then
87
return false
88
fi
89
90
let owner = to_string.owner
91
92
return
93
owner? /\
94
owner != _lookup.get_object_type().symbol /\
95
owner != _lookup.get_value_type().symbol
96
si
97
98
// The overload of the runtime's `$` that renders any value, or
99
// null where the runtime referenced has no `$`.
100
display_function: Symbols.Function? is
101
if let functions = _lookup.get_display_functions() then
102
for function in functions.functions do
103
if !function.is_generic /\ function.arguments.count == 1 then
104
let parameter = function.arguments[0].type!
105
106
if (parameter.optional_inner_type ?? parameter).is_object then
107
return function
108
fi
109
fi
110
od
111
fi
112
113
return null
114
si
115
116
_is(type: Type, other: Type) -> bool =>
117
type.compare(other) == Types.MATCH.SAME
118
119
zero_argument_to_string(member: Symbols.Symbol?) -> Symbols.Function? static is
120
if let group: Symbols.FUNCTION_GROUP = member then
121
for function in group.functions do
122
if !function.are_arguments_declared \/ function.arguments.count == 0 then
123
return function
124
fi
125
od
126
fi
127
128
return null
129
si
130
si
131
si