diff --git a/docs/changelog.md b/docs/changelog.md index 935b6f5680..c232260e01 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -16,6 +16,9 @@ what we publish. ### ⭐️ New +- `StringRef` is now representable so `repr(StringRef("hello"))` will return + `StringRef('hello')`. + - Mojo can now interpret simple LLVM intrinsics in parameter expressions, enabling things like `count_leading_zeros` to work at compile time: [Issue #933](https://github.com/modularml/mojo/issues/933). diff --git a/stdlib/src/builtin/dtype.mojo b/stdlib/src/builtin/dtype.mojo index e0b81dadc7..fa7a222492 100644 --- a/stdlib/src/builtin/dtype.mojo +++ b/stdlib/src/builtin/dtype.mojo @@ -217,7 +217,7 @@ struct DType( Returns: The representation of the dtype. """ - return "DType." + str(self) + return String.write("DType.", self) @always_inline("nodebug") fn get_value(self) -> __mlir_type.`!kgen.dtype`: diff --git a/stdlib/src/builtin/error.mojo b/stdlib/src/builtin/error.mojo index 482f4aa454..5e74bdff77 100644 --- a/stdlib/src/builtin/error.mojo +++ b/stdlib/src/builtin/error.mojo @@ -180,7 +180,7 @@ struct Error( Returns: A printable representation of the error message. """ - return "Error(" + repr(self._message()) + ")" + return String.write("Error(", repr(self._message()), ")") # ===-------------------------------------------------------------------===# # Methods diff --git a/stdlib/src/builtin/uint.mojo b/stdlib/src/builtin/uint.mojo index cc9f9b8d22..03bb691300 100644 --- a/stdlib/src/builtin/uint.mojo +++ b/stdlib/src/builtin/uint.mojo @@ -149,7 +149,7 @@ struct UInt(IntLike, _HashableWithHasher): Returns: The string representation of this UInt. """ - return "UInt(" + str(self) + ")" + return String.write("UInt(", str(self), ")") fn __hash__(self) -> UInt: """Hash the UInt using builtin hash. diff --git a/stdlib/src/os/fstat.mojo b/stdlib/src/os/fstat.mojo index f3d367944e..ba298916d4 100644 --- a/stdlib/src/os/fstat.mojo +++ b/stdlib/src/os/fstat.mojo @@ -46,7 +46,7 @@ fn _constrain_unix(): @value -struct stat_result(Stringable): +struct stat_result(Stringable, Writable): """Object whose fields correspond to the members of the stat structure.""" var st_mode: Int @@ -150,6 +150,35 @@ struct stat_result(Stringable): self.st_rdev = st_rdev self.st_flags = st_flags + @no_inline + fn write_to[W: Writer](self, inout writer: W): + """ + Formats this path to the provided Writer. + + Parameters: + W: A type conforming to the Writable trait. + + Args: + writer: The object to write to. + """ + writer.write("os.stat_result(") + writer.write("st_mode=", self.st_mode) + writer.write(", st_ino=", self.st_ino) + writer.write(", st_dev=", self.st_dev) + writer.write(", st_nlink=", self.st_nlink) + writer.write(", st_uid=", self.st_uid) + writer.write(", st_gid=", self.st_gid) + writer.write(", st_size=", self.st_size) + writer.write(", st_atime=", str(self.st_atimespec)) + writer.write(", st_mtime=", str(self.st_mtimespec)) + writer.write(", st_ctime=", str(self.st_ctimespec)) + writer.write(", st_birthtime=", str(self.st_birthtimespec)) + writer.write(", st_blocks=", self.st_blocks) + writer.write(", st_blksize=", self.st_blksize) + writer.write(", st_rdev=", self.st_rdev) + writer.write(", st_flags=", self.st_flags) + writer.write(")") + @no_inline fn __str__(self) -> String: """Constructs a string representation of stat_result. @@ -157,23 +186,7 @@ struct stat_result(Stringable): Returns: A string representation of stat_result. """ - var res = String("os.stat_result(") - res += "st_mode=" + str(self.st_mode) - res += ", st_ino=" + str(self.st_ino) - res += ", st_dev=" + str(self.st_dev) - res += ", st_nlink=" + str(self.st_nlink) - res += ", st_uid=" + str(self.st_uid) - res += ", st_gid=" + str(self.st_gid) - res += ", st_size=" + str(self.st_size) - res += ", st_atime=" + str(self.st_atimespec) - res += ", st_mtime=" + str(self.st_mtimespec) - res += ", st_ctime=" + str(self.st_ctimespec) - res += ", st_birthtime=" + str(self.st_birthtimespec) - res += ", st_blocks=" + str(self.st_blocks) - res += ", st_blksize=" + str(self.st_blksize) - res += ", st_rdev=" + str(self.st_rdev) - res += ", st_flags=" + str(self.st_flags) - return res + ")" + return String.write(self) fn __repr__(self) -> String: """Constructs a representation of stat_result. diff --git a/stdlib/src/utils/stringref.mojo b/stdlib/src/utils/stringref.mojo index 8406c7451e..0d1ede078e 100644 --- a/stdlib/src/utils/stringref.mojo +++ b/stdlib/src/utils/stringref.mojo @@ -41,17 +41,18 @@ fn _align_down(value: Int, alignment: Int) -> Int: @value @register_passable("trivial") struct StringRef( - Sized, - IntableRaising, + AsBytes, + Boolable, CollectionElement, CollectionElementNew, + Comparable, + Hashable, + IntableRaising, + Representable, + Sized, Stringable, Writable, - Hashable, _HashableWithHasher, - Boolable, - Comparable, - AsBytes, ): """ Represent a constant reference to a string, i.e. a sequence of characters @@ -396,6 +397,15 @@ struct StringRef( """ return String.write(self) + @no_inline + fn __repr__(self) -> String: + """Convert the string reference to a string. + + Returns: + The String representation of the StringRef. + """ + return String.write("StringRef(", repr(str(self)), ")") + @no_inline fn write_to[W: Writer](self, inout writer: W): """ diff --git a/stdlib/test/pathlib/test_pathlib.mojo b/stdlib/test/pathlib/test_pathlib.mojo index 249d5b2133..fc54c8f8d4 100644 --- a/stdlib/test/pathlib/test_pathlib.mojo +++ b/stdlib/test/pathlib/test_pathlib.mojo @@ -148,6 +148,34 @@ def test_home(): set_home(original_home) +def test_stat(): + var path = Path(__source_location().file_name) + var stat = path.stat() + assert_equal( + str(stat), + "os.stat_result(st_mode={}, st_ino={}, st_dev={}, st_nlink={}," + " st_uid={}, st_gid={}, st_size={}, st_atime={}, st_mtime={}," + " st_ctime={}, st_birthtime={}, st_blocks={}, st_blksize={}," + " st_rdev={}, st_flags={})".format( + stat.st_mode, + stat.st_ino, + stat.st_dev, + stat.st_nlink, + stat.st_uid, + stat.st_gid, + stat.st_size, + str(stat.st_atimespec), + str(stat.st_mtimespec), + str(stat.st_ctimespec), + str(stat.st_birthtimespec), + stat.st_blocks, + stat.st_blksize, + stat.st_rdev, + stat.st_flags, + ), + ) + + def main(): test_cwd() test_path() @@ -159,3 +187,4 @@ def main(): test_read_write() test_expand_user() test_home() + test_stat() diff --git a/stdlib/test/utils/test_stringref.mojo b/stdlib/test/utils/test_stringref.mojo index 33c18c533f..0dc7686197 100644 --- a/stdlib/test/utils/test_stringref.mojo +++ b/stdlib/test/utils/test_stringref.mojo @@ -169,6 +169,25 @@ fn test_stringref_split() raises: assert_equal(res4[1], "o") +def test_str_and_ref(): + assert_equal(StringRef("abc").__str__(), "abc") + assert_equal(StringRef("abc").__repr__(), "StringRef('abc')") + assert_equal(StringRef("\0").__repr__(), r"StringRef('\x00')") + assert_equal(StringRef("\x09").__repr__(), r"StringRef('\t')") + assert_equal(StringRef("\n").__repr__(), r"StringRef('\n')") + assert_equal(StringRef("\x0d").__repr__(), r"StringRef('\r')") + assert_equal(StringRef("'").__repr__(), 'StringRef("\'")') + + # Multi-byte characters.__repr__() + assert_equal( + StringRef("Örnsköldsvik").__repr__(), "StringRef('Örnsköldsvik')" + ) # 2-byte + assert_equal(StringRef("你好!").__repr__(), "StringRef('你好!')") # 3-byte + assert_equal( + StringRef("hello 🔥!").__repr__(), "StringRef('hello 🔥!')" + ) # 4-byte + + def main(): test_strref_from_start() test_stringref_split() @@ -177,3 +196,4 @@ def main(): test_indexing() test_find() test_endswith() + test_str_and_ref()