Appearance
| 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 |