Skip to content
← Back

src/semantic/types/function.ghul

1
namespace Semantic.Types is
2
use Source.LOCATION
3
4
use Ghul.Pipes
5
6
class FUNCTION: GENERIC is
7
is_function: bool => true
8
9
short_description: string => with_optionality(self, get_short_description(self))
10
11
// An optional function type keeps its parentheses around the
12
// shape, so `(() -> int)?` reads as one optional function.
13
with_optionality(function: Type, text: string) -> string static =>
14
if function.is_optional then "({text})?" else text fi
15
16
get_short_description(function: GENERIC) -> string static is
17
let result = System.Text.StringBuilder()
18
19
let args = function.arguments
20
21
if args.count == 2 then
22
result
23
.append(FUNCTION.lone_parameter_description(args[0]))
24
.append(" -> ")
25
.append(FUNCTION.return_description(args[1]))
26
elif args.count == 1 then
27
result
28
.append("() -> ")
29
.append(FUNCTION.return_description(args[0]))
30
else
31
result.append('(')
32
33
(0..args.count-1) |> map(i => args[i]) |> append_to(result)
34
35
result
36
.append(") -> ")
37
.append(FUNCTION.return_description(args[args.count-1]))
38
fi
39
40
return result.to_string()
41
si
42
43
// A returned pure function keeps its parentheses, so the purity
44
// that belongs to it is not read as the outer function's:
45
// `int -> ((int) -> int pure)` rather than `int -> int -> int pure`.
46
return_description(result: Type) -> string static =>
47
if result.is_pure_function then "({result})" else "{result}" fi
48
49
// A lone parameter that is itself a tuple or a function keeps
50
// its own parentheses, so that `((int, int)) -> int` is not
51
// written as the two-parameter `(int, int) -> int`, nor
52
// `(int -> int) -> int` as a curried `int -> int -> int`.
53
lone_parameter_description(parameter: Type) -> string static =>
54
if isa TUPLE(parameter) \/ isa ARRAY(parameter) \/ parameter.is_value_tuple \/ parameter.is_function then
55
"({parameter})"
56
else
57
"{parameter}"
58
fi
59
60
init(
61
location: LOCATION,
62
symbol: Symbols.Classy,
63
arguments: Collections.List[Type]
64
) is
65
super.init(location, symbol, arguments)
66
si
67
68
get_argument_type_variance(index: int) -> TypeVariance =>
69
if index == arguments.count - 1 then
70
TypeVariance.COVARIANT
71
else
72
TypeVariance.CONTRAVARIANT
73
fi
74
75
create(
76
location: LOCATION,
77
symbol: Symbols.Classy,
78
arguments: Collections.List[Type]
79
) -> GENERIC =>
80
FUNCTION(location, symbol, arguments)
81
82
to_string() -> string => with_optionality(self, get_short_description(self))
83
si
84
si