diff --git a/argparse/error.mbt b/argparse/error.mbt index 386eaddc5..e8dc07b35 100644 --- a/argparse/error.mbt +++ b/argparse/error.mbt @@ -29,6 +29,32 @@ impl Show for ArgError with output(self : ArgError, logger) { } } +///| +impl @debug.Debug for ArgError with to_repr(self) { + match self { + Message(msg) => @debug.Repr::literal(msg) + } +} + +///| +test "ArgError debug keeps display text" { + let err : Error = ArgError::Message( + ( + $|error: unexpected argument '--bad' found + $| + $|Usage: demo [options] + ), + ) + inspect( + err.to_string(), + content=( + #|error: unexpected argument '--bad' found + #| + #|Usage: demo [options] + ), + ) +} + ///| /// Internal parse error variants used while parsing. priv suberror ArgParseError { diff --git a/builtin/autoloc.mbt b/builtin/autoloc.mbt index c6fa3c542..d55416b45 100644 --- a/builtin/autoloc.mbt +++ b/builtin/autoloc.mbt @@ -40,8 +40,8 @@ pub(all) type SourceLoc fn SourceLoc::repr(self : Self) -> String = "%loc_to_string" ///| -pub impl Show for SourceLoc with output(self, logger) { - logger.write_string(self.repr()) +pub impl Show for SourceLoc with to_string(self) { + self.repr() } ///| diff --git a/builtin/double.mbt b/builtin/double.mbt index 79abf94d1..25922a8b8 100644 --- a/builtin/double.mbt +++ b/builtin/double.mbt @@ -290,8 +290,8 @@ pub fn Double::to_string(self : Double) -> String { // } ///| -pub impl Show for Double with output(self, logger) { - logger.write_string(self.to_string()) +pub impl Show for Double with to_string(self) { + Double::to_string(self) } ///| diff --git a/builtin/feature_test.mbt b/builtin/feature_test.mbt index e0b639e83..50669a27c 100644 --- a/builtin/feature_test.mbt +++ b/builtin/feature_test.mbt @@ -16,7 +16,7 @@ struct RangeImpl[T] { lo : T hi : T -} derive(Show, ToJson) +} derive(ToJson) // pub // priv diff --git a/builtin/guard_feature_test.mbt b/builtin/guard_feature_test.mbt index 40f6142fc..c9959596f 100644 --- a/builtin/guard_feature_test.mbt +++ b/builtin/guard_feature_test.mbt @@ -20,7 +20,7 @@ enum Expr { Div(Expr, Expr) Lit(Int) Var(String) -} derive(Show, ToJson, Eq) +} derive(ToJson, Eq) ///| fn simplify(e : Expr) -> Expr { diff --git a/builtin/pkg.generated.mbti b/builtin/pkg.generated.mbti index 45e6443fc..6b27b2ab1 100644 --- a/builtin/pkg.generated.mbti +++ b/builtin/pkg.generated.mbti @@ -1305,8 +1305,9 @@ pub impl Shl for UInt pub impl Shl for UInt16 pub impl Shl for UInt64 +#must_implement_one(output, to_string) pub(open) trait Show { - output(Self, &Logger) -> Unit + output(Self, &Logger) -> Unit = _ to_string(Self) -> String = _ } pub impl Show for Unit diff --git a/builtin/show.mbt b/builtin/show.mbt index b40fb4505..18b9d6730 100644 --- a/builtin/show.mbt +++ b/builtin/show.mbt @@ -13,47 +13,47 @@ // limitations under the License. ///| -pub impl Show for Unit with output(_self, logger) { - logger.write_string("()") +pub impl Show for Unit with to_string(_self) { + "()" } ///| -pub impl Show for Bool with output(self, logger) { +pub impl Show for Bool with to_string(self) { if self { - logger.write_string("true") + "true" } else { - logger.write_string("false") + "false" } } ///| -pub impl Show for Int with output(self, logger) { - logger.write_string(self.to_string()) +pub impl Show for Int with to_string(self) { + Int::to_string(self) } ///| -pub impl Show for Int64 with output(self, logger) { - logger.write_string(self.to_string()) +pub impl Show for Int64 with to_string(self) { + Int64::to_string(self) } ///| -pub impl Show for UInt with output(self, logger) { - logger.write_string(self.to_string()) +pub impl Show for UInt with to_string(self) { + UInt::to_string(self) } ///| -pub impl Show for UInt64 with output(self, logger) { - logger.write_string(self.to_string()) +pub impl Show for UInt64 with to_string(self) { + UInt64::to_string(self) } ///| -pub impl Show for Byte with output(self, logger) { - logger.write_string(self.to_string()) +pub impl Show for Byte with to_string(self) { + Byte::to_string(self) } ///| -pub impl Show for UInt16 with output(self, logger) { - logger.write_string(self.to_string()) +pub impl Show for UInt16 with to_string(self) { + UInt16::to_string(self) } ///| diff --git a/builtin/traits.mbt b/builtin/traits.mbt index 87e89c687..a52cecc18 100644 --- a/builtin/traits.mbt +++ b/builtin/traits.mbt @@ -123,22 +123,32 @@ impl Logger with write_char(self, value) { ///| /// Trait for types that can be converted to `String` +#must_implement_one(output, to_string) pub(open) trait Show { // `output` is used for composition of aggregate structure. // `output` writes a string representation of `self` to a logger. // `output` should produce a valid MoonBit-syntax representation if possible. // For example, `Show::output` for `String` should be quoted - output(Self, &Logger) -> Unit + // By default `output` is implemented using `to_string`, + // but some types, such as `String` and `Char`, may override `output`, + // for different (escaped) behavior when composed into larger structures. + output(Self, &Logger) -> Unit = _ // `to_string` should be used by end users of `Show`, // for printing, interpolation, etc. only, and should not be used for composition. // By default `to_string` is implemented using `output` and a buffer, // but some types, such as `String`, may override `to_string`, - // for different (unescaped) behavior when interpolated/printed directly + // for different (unescaped) behavior when interpolated/printed directly. to_string(Self) -> String = _ } ///| -/// Default implementation for `Show::to_string`, uses a `StringBuilder` +/// Default implementation for `Show::output`, uses `Show::to_string`. +impl Show with output(self, logger) { + logger.write_string(self.to_string()) +} + +///| +/// Default implementation for `Show::to_string`, uses a `StringBuilder`. impl Show with to_string(self) { let logger = StringBuilder::new() self.output(logger) diff --git a/error/error.mbt b/error/error.mbt index 6e612397a..488bc53ac 100644 --- a/error/error.mbt +++ b/error/error.mbt @@ -13,7 +13,9 @@ // limitations under the License. ///| -fn Error::to_string(self : Error) -> String = "%error.to_string" +fn Error::to_string(self : Error) -> String { + @debug.to_string(self) +} ///| /// Implements `Show` trait for `Error` type by converting the error into a diff --git a/error/error_test.mbt b/error/error_test.mbt index d3fcd6fb9..e178ec8ae 100644 --- a/error/error_test.mbt +++ b/error/error_test.mbt @@ -30,7 +30,12 @@ test "show error" { inspect(try! f(true), content="ok") inspect( try? f(false), - content="Err(moonbitlang/core/error_blackbox_test.IntError.IntError)", + content="Err()", + ) + inspect( + (IntError(42) : Error).to_string() == + @debug.to_string((IntError(42) : Error)), + content="true", ) } diff --git a/json/derive_json_test.mbt b/json/derive_json_test.mbt index 05ec470ff..bdef45188 100644 --- a/json/derive_json_test.mbt +++ b/json/derive_json_test.mbt @@ -17,7 +17,7 @@ struct Hello[A, B] { fieldA : A fieldB : B data : Map[String, A] -} derive(ToJson, FromJson, Show, Eq) +} derive(ToJson, FromJson, Debug, Eq) ///| test { @@ -25,12 +25,12 @@ test { let vj = v.to_json() let v0 : Hello[Int, Int] = @json.from_json(vj) inspect( - v0, + v0.to_json(), content=( - #|{fieldA: 3, fieldB: 2, data: {"a": 3}} + #|Object({"fieldA": Number(3), "fieldB": Number(2), "data": Object({"a": Number(3)})}) ), ) - assert_eq(v0, v) + assert_true(v0 == v) } // struct Hello2 [A, B] { diff --git a/json/from_to_json_test.mbt b/json/from_to_json_test.mbt index c3b26c962..f8e01ba90 100644 --- a/json/from_to_json_test.mbt +++ b/json/from_to_json_test.mbt @@ -19,7 +19,7 @@ enum Expr { Mul(Expr, Expr) Div(Expr, Expr) Val(String) -} derive(ToJson, FromJson, Show, Eq) +} derive(ToJson, FromJson, Debug, Eq) ///| test { @@ -33,10 +33,10 @@ test { ) let e0 : Expr = @json.from_json(ej) inspect( - e0, + e0.to_json().stringify(), content=( - #|Add(Val("x"), Val("y")) + #|["Add",["Val","x"],["Val","y"]] ), ) - assert_eq(e0, e) + assert_true(e0 == e) } diff --git a/json/json_encode_decode_test.mbt b/json/json_encode_decode_test.mbt index 83d2ec60b..7a3588945 100644 --- a/json/json_encode_decode_test.mbt +++ b/json/json_encode_decode_test.mbt @@ -18,7 +18,7 @@ pub(all) struct AllThree { ints : Array[Int] floats : Array[Double] strings : Array[String] -} derive(Eq, Show) +} derive(Eq, Debug) ///| fn[T] array_to_json(arr : Array[T], f~ : (T) -> Json) -> Json { @@ -38,7 +38,7 @@ fn AllThree::to_json(self : AllThree) -> Json { ///| suberror DecodeError { DecodeError(String) -} derive(Eq, Show) +} derive(Eq, Debug) ///| fn of_json(jv : Json) -> AllThree raise DecodeError { @@ -85,9 +85,9 @@ test { } let json = all_three.to_json() inspect( - try? of_json(json), + (try! of_json(json)).to_json(), content=( - #|Ok({ints: [1, 2, 3], floats: [1, 2, 3], strings: ["a", "b", "c"]}) + #|Object({"ints": Array([Number(1), Number(2), Number(3)]), "floats": Array([Number(1), Number(2), Number(3)]), "strings": Array([String("a"), String("b"), String("c")])}) ), ) // FIXME: diff --git a/json/to_json_test.mbt b/json/to_json_test.mbt index 1323b8230..f86a147dd 100644 --- a/json/to_json_test.mbt +++ b/json/to_json_test.mbt @@ -200,7 +200,7 @@ test "Map::to_json" { struct Opt { x : Int? t : Int?? -} derive(ToJson, FromJson, Eq, Show) +} derive(ToJson, FromJson, Eq, Debug) ///| test "Option::to_json" { @@ -231,11 +231,11 @@ test "optional field" { ///| test "optional field round trip" { let opt = { x: Some(42), t: Some(Some(42)) } - assert_eq(@json.from_json(opt.to_json()), opt) + assert_true(@json.from_json(opt.to_json()) == opt) let opt = { x: None, t: None } - assert_eq(@json.from_json(opt.to_json()), opt) + assert_true(@json.from_json(opt.to_json()) == opt) let opt = { x: None, t: Some(None) } - assert_eq(@json.from_json(opt.to_json()), opt) + assert_true(@json.from_json(opt.to_json()) == opt) } ///|