From 1a4400a374604b603bfe74511f17201ede4c489a Mon Sep 17 00:00:00 2001 From: Gears Date: Sat, 11 Oct 2025 22:27:05 +0100 Subject: [PATCH] Implement type annotation printing --- birdie_snapshots/anonymous_function.accepted | 2 +- ...function_with_multiple_statements.accepted | 2 +- birdie_snapshots/constant.accepted | 2 +- .../constant_referencing_function.accepted | 6 +- .../constant_used_in_function.accepted | 4 +- birdie_snapshots/function.accepted | 2 +- birdie_snapshots/function_capture.accepted | 2 +- birdie_snapshots/labelled_parameter.accepted | 4 +- birdie_snapshots/long_call.accepted | 2 +- birdie_snapshots/multiple_constants.accepted | 6 +- birdie_snapshots/multiple_functions.accepted | 4 +- birdie_snapshots/recursive_function.accepted | 2 +- .../type_annotation_printing.accepted | 15 ++++ src/trick.gleam | 82 ++++++++++++++++++- test/trick_test.gleam | 25 ++++++ 15 files changed, 140 insertions(+), 20 deletions(-) create mode 100644 birdie_snapshots/type_annotation_printing.accepted diff --git a/birdie_snapshots/anonymous_function.accepted b/birdie_snapshots/anonymous_function.accepted index 476433f..d732a94 100644 --- a/birdie_snapshots/anonymous_function.accepted +++ b/birdie_snapshots/anonymous_function.accepted @@ -5,6 +5,6 @@ file: ./test/trick_test.gleam test_name: anonymous_function_test --- { - let f = fn(a, b) { a + b } + let f = fn(a: Int, b: Int) { a + b } f(1, 2) } diff --git a/birdie_snapshots/anonymous_function_with_multiple_statements.accepted b/birdie_snapshots/anonymous_function_with_multiple_statements.accepted index aa23d1d..b4d5539 100644 --- a/birdie_snapshots/anonymous_function_with_multiple_statements.accepted +++ b/birdie_snapshots/anonymous_function_with_multiple_statements.accepted @@ -4,7 +4,7 @@ title: anonymous_function_with_multiple_statements file: ./test/trick_test.gleam test_name: anonymous_function_with_multiple_statements_test --- -fn(a, b) { +fn(a: Int, b: Int) { let c = a + b echo c c diff --git a/birdie_snapshots/constant.accepted b/birdie_snapshots/constant.accepted index 72a1fa6..9d0540c 100644 --- a/birdie_snapshots/constant.accepted +++ b/birdie_snapshots/constant.accepted @@ -4,6 +4,6 @@ title: constant file: ./test/trick_test.gleam test_name: constant_test --- -const pi = 3.14 +const pi: Float = 3.14 diff --git a/birdie_snapshots/constant_referencing_function.accepted b/birdie_snapshots/constant_referencing_function.accepted index 151fd90..672800a 100644 --- a/birdie_snapshots/constant_referencing_function.accepted +++ b/birdie_snapshots/constant_referencing_function.accepted @@ -4,12 +4,12 @@ title: constant_referencing_function file: ./test/trick_test.gleam test_name: constant_referencing_function_test --- -const pi = 3.14 +const pi: Float = 3.14 -fn area(radius) { +fn area(radius: Float) -> Float { pi *. radius *. radius } -const area2 = area +const area2: fn(Float) -> Float = area diff --git a/birdie_snapshots/constant_used_in_function.accepted b/birdie_snapshots/constant_used_in_function.accepted index 30882db..5d8f26c 100644 --- a/birdie_snapshots/constant_used_in_function.accepted +++ b/birdie_snapshots/constant_used_in_function.accepted @@ -4,9 +4,9 @@ title: constant_used_in_function file: ./test/trick_test.gleam test_name: constant_used_in_function_test --- -const pi = 3.14 +const pi: Float = 3.14 -fn area(radius) { +fn area(radius: Float) -> Float { pi *. radius *. radius } diff --git a/birdie_snapshots/function.accepted b/birdie_snapshots/function.accepted index 2c83c3a..e2f3868 100644 --- a/birdie_snapshots/function.accepted +++ b/birdie_snapshots/function.accepted @@ -4,7 +4,7 @@ title: function file: ./test/trick_test.gleam test_name: function_test --- -fn add(a, b) { +fn add(a: Int, b: Int) -> Int { a + b } diff --git a/birdie_snapshots/function_capture.accepted b/birdie_snapshots/function_capture.accepted index 993012c..21ff926 100644 --- a/birdie_snapshots/function_capture.accepted +++ b/birdie_snapshots/function_capture.accepted @@ -5,7 +5,7 @@ file: ./test/trick_test.gleam test_name: function_capture_test --- { - let add = fn(a, b) { a + b } + let add = fn(a: Int, b: Int) { a + b } let add_one = add(_, 1) add_one(5) + 1 } diff --git a/birdie_snapshots/labelled_parameter.accepted b/birdie_snapshots/labelled_parameter.accepted index 895aa5f..a38b426 100644 --- a/birdie_snapshots/labelled_parameter.accepted +++ b/birdie_snapshots/labelled_parameter.accepted @@ -4,11 +4,11 @@ title: labelled_parameter file: ./test/trick_test.gleam test_name: labelled_parameter_test --- -fn add(a a, b b) { +fn add(a a: Int, b b: Int) -> Int { a + b } -fn main() { +fn main() -> Int { add(1, 2) } diff --git a/birdie_snapshots/long_call.accepted b/birdie_snapshots/long_call.accepted index 55c7ccd..a5f59bb 100644 --- a/birdie_snapshots/long_call.accepted +++ b/birdie_snapshots/long_call.accepted @@ -5,7 +5,7 @@ file: ./test/trick_test.gleam test_name: long_call_test --- { - let concat = fn(a, b) { a <> b } + let concat = fn(a: String, b: String) { a <> b } concat( "This string is pretty long by itself, but", " combined with this one it goes over the line limit", diff --git a/birdie_snapshots/multiple_constants.accepted b/birdie_snapshots/multiple_constants.accepted index 95e0451..c9de475 100644 --- a/birdie_snapshots/multiple_constants.accepted +++ b/birdie_snapshots/multiple_constants.accepted @@ -4,10 +4,10 @@ title: multiple_constants file: ./test/trick_test.gleam test_name: multiple_constants_test --- -const pi = 3.14 +const pi: Float = 3.14 -const e = 2.71 +const e: Float = 2.71 -const mathematical_constants = #(e, pi) +const mathematical_constants: #(Float, Float) = #(e, pi) diff --git a/birdie_snapshots/multiple_functions.accepted b/birdie_snapshots/multiple_functions.accepted index cd3c32a..76f64c4 100644 --- a/birdie_snapshots/multiple_functions.accepted +++ b/birdie_snapshots/multiple_functions.accepted @@ -4,11 +4,11 @@ title: multiple_functions file: ./test/trick_test.gleam test_name: multiple_functions_test --- -fn add(a, b) { +fn add(a: Int, b: Int) -> Int { a + b } -fn main() { +fn main() -> Nil { echo add(1, 2) Nil } diff --git a/birdie_snapshots/recursive_function.accepted b/birdie_snapshots/recursive_function.accepted index 2e6cac5..f717017 100644 --- a/birdie_snapshots/recursive_function.accepted +++ b/birdie_snapshots/recursive_function.accepted @@ -4,7 +4,7 @@ title: recursive_function file: ./test/trick_test.gleam test_name: recursive_function_test --- -fn add(a a, b b) { +fn add(a a: Int, b b: Int) -> a { add(a, b) } diff --git a/birdie_snapshots/type_annotation_printing.accepted b/birdie_snapshots/type_annotation_printing.accepted new file mode 100644 index 0000000..37ddb58 --- /dev/null +++ b/birdie_snapshots/type_annotation_printing.accepted @@ -0,0 +1,15 @@ +--- +version: 1.4.1 +title: type_annotation_printing +file: ./test/trick_test.gleam +test_name: type_annotation_printing_test +--- +fn main( + tuple: #(Int, Float, String), + function: fn(Int, Int) -> Float, + generic: de, +) -> #(#(Int, Float, String), fn(Int, Int) -> Float, de) { + #(tuple, function, generic) +} + + diff --git a/src/trick.gleam b/src/trick.gleam index c296558..ce869d3 100644 --- a/src/trick.gleam +++ b/src/trick.gleam @@ -6,6 +6,7 @@ import gleam/int import gleam/list import gleam/option.{type Option, None, Some} import gleam/result +import gleam/string import lazy_const import splitter @@ -863,12 +864,19 @@ pub fn labelled_parameter( fn parameter_to_doc(parameter: Parameter) -> Document { case parameter.label { - None -> doc.from_string(parameter.name) + None -> + doc.concat([ + doc.from_string(parameter.name), + doc.from_string(": "), + doc.from_string(print_type(parameter.type_)), + ]) Some(label) -> doc.concat([ doc.from_string(label), doc.from_string(" "), doc.from_string(parameter.name), + doc.from_string(": "), + doc.from_string(print_type(parameter.type_)), ]) } } @@ -1095,6 +1103,8 @@ pub fn function( doc.from_string("fn "), doc.from_string(name), parameter_list, + doc.from_string(" -> "), + doc.from_string(print_type(return_type)), doc.from_string(" "), body_doc, doc.lines(2), @@ -1126,6 +1136,8 @@ pub fn constant( [ doc.from_string("const "), doc.from_string(name), + doc.from_string(": "), + doc.from_string(print_type(value.type_)), doc.from_string(" = "), value.document, doc.lines(2), @@ -1135,6 +1147,74 @@ pub fn constant( |> Compiled(value.type_) |> return } + +fn print_type(type_: Type) -> String { + case type_ { + Custom(module: _, name:, generics:) -> + case generics { + [] -> name + _ -> + name + <> "(" + <> string.join(list.map(generics, print_type), ", ") + <> ")" + } + Function(parameters:, return:) -> + "fn(" + <> string.join(list.map(parameters, print_type), ", ") + <> ") -> " + <> print_type(return) + Tuple(elements:) -> + "#(" <> string.join(list.map(elements, print_type), ", ") <> ")" + TypeVariable(id:) -> generate_type_variable_name(id) + } +} + +fn generate_type_variable_name(id: Int) -> String { + generate_type_variable_name_loop(id, "") +} + +fn generate_type_variable_name_loop(id: Int, name: String) -> String { + case id < 26 { + True -> letter(id) <> name + False -> { + let name = letter(id % 26) <> name + let id = id / 26 + generate_type_variable_name_loop(id, name) + } + } +} + +fn letter(id: Int) -> String { + case id { + 0 -> "a" + 1 -> "b" + 2 -> "c" + 3 -> "d" + 4 -> "e" + 5 -> "f" + 6 -> "g" + 7 -> "h" + 8 -> "i" + 9 -> "j" + 10 -> "k" + 11 -> "l" + 12 -> "m" + 13 -> "n" + 14 -> "o" + 15 -> "p" + 16 -> "q" + 17 -> "r" + 18 -> "s" + 19 -> "t" + 20 -> "u" + 21 -> "v" + 22 -> "w" + 23 -> "x" + 24 -> "y" + _ -> "z" + } +} // TODO: // BitString // Case diff --git a/test/trick_test.gleam b/test/trick_test.gleam index 520f80d..4d01037 100644 --- a/test/trick_test.gleam +++ b/test/trick_test.gleam @@ -904,3 +904,28 @@ pub fn constant_type_checks_correctly_test() { assert error == trick.TypeMismatch(expected: type_int, got: type_float) } + +pub fn type_annotation_printing_test() { + trick.function( + "main", + { + use tuple <- trick.parameter( + "tuple", + trick.Tuple([type_int, type_float, type_string]), + ) + use function <- trick.parameter( + "function", + trick.Function([type_int, type_int], type_float), + ) + use generic <- trick.parameter("generic", trick.TypeVariable(82)) + [tuple, function, generic] + |> trick.tuple + |> trick.expression + |> trick.function_body + }, + fn(_) { trick.empty() }, + ) + |> trick.to_string + |> unwrap + |> birdie.snap("type_annotation_printing") +} -- 2.51.2