From d6096294890969ab7a09a005ddda6984d1defa4f Mon Sep 17 00:00:00 2001 From: "A. R. Shajii" Date: Tue, 2 Jan 2024 13:35:55 -0500 Subject: [PATCH] Format 1-element tuples as "(x,)" (#521) * Format 1-element tuples as "(x,)" Currently, single-element tuple "repr" / "str" gives "(x)", but it should really give "(x,)" according to Python. * Fix tests --- stdlib/internal/internal.codon | 10 ++++++++++ test/core/containers.codon | 7 +++++++ test/parser/simplify_expr.codon | 2 +- test/parser/typecheck_expr.codon | 8 ++++---- test/parser/typecheck_stmt.codon | 2 +- test/parser/types.codon | 8 ++++---- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/stdlib/internal/internal.codon b/stdlib/internal/internal.codon index a40cf100..17b8eef4 100644 --- a/stdlib/internal/internal.codon +++ b/stdlib/internal/internal.codon @@ -427,6 +427,16 @@ class __internal__: return str(buf, total) def tuple_str(strs: Ptr[str], names: Ptr[str], n: int) -> str: + # special case of 1-element plain tuple: format as "(x,)" + if n == 1 and names[0].len == 0: + total = strs[0].len + 3 + buf = Ptr[byte](total) + buf[0] = byte(40) # '(' + str.memcpy(buf + 1, strs[0].ptr, strs[0].len) + buf[total - 2] = byte(44) # ',' + buf[total - 1] = byte(41) # ')' + return str(buf, total) + total = 2 # one for each of '(' and ')' i = 0 while i < n: diff --git a/test/core/containers.codon b/test/core/containers.codon index de17ed05..ec38b0d0 100644 --- a/test/core/containers.codon +++ b/test/core/containers.codon @@ -93,6 +93,13 @@ def test_tuple(): assert a[0:] == 3 assert a[0:1] == 42 assert a[:] == -1 + + assert str((11, 2, 333)) == '(11, 2, 333)' + assert str(()) == '()' + assert str((42,)) == '(42,)' + assert repr((11, 2, 333)) == '(11, 2, 333)' + assert repr(()) == '()' + assert repr((42,)) == '(42,)' test_tuple() @test diff --git a/test/parser/simplify_expr.codon b/test/parser/simplify_expr.codon index 872c056e..95ad691e 100644 --- a/test/parser/simplify_expr.codon +++ b/test/parser/simplify_expr.codon @@ -255,7 +255,7 @@ t: tuple[int, int] = (1, 2) print t #: (1, 2) tt: Tuple[int] = (1, ) -print tt #: (1) +print tt #: (1,) def foo(i: int) -> int: return i + 1 diff --git a/test/parser/typecheck_expr.codon b/test/parser/typecheck_expr.codon index 7be6e8aa..78ba102a 100644 --- a/test/parser/typecheck_expr.codon +++ b/test/parser/typecheck_expr.codon @@ -206,7 +206,7 @@ print z[:1], z[1:], z[1:3], z[:4:2], z[::-1] #: [1] [2, 3, 4, 5] [2, 3] [1, 3] a = (1, '2s', 3.3) print a[1] #: 2s print a[0:2], a[:2], a[1:] #: (1, '2s') (1, '2s') ('2s', 3.3) -print a[0:3:2], a[-1:] #: (1, 3.3) (3.3) +print a[0:3:2], a[-1:] #: (1, 3.3) (3.3,) #%% static_index_side,barebones def foo(a): @@ -470,14 +470,14 @@ p('s', zh=65) #: s () (zh: 65) q = p(zh=43, ...) q(1) #: 1 () (zh: 43) r = q(5, 38, ...) -r() #: 5 (38) (zh: 43) +r() #: 5 (38,) (zh: 43) r(1, a=1) #: 5 (38, 1) (zh: 43, a: 1) #%% call_args_kwargs_type,barebones def foo(*args: float, **kwargs: int): print(args, kwargs, args.__class__.__name__) -foo(1, f=1) #: (1) (f: 1) Tuple[float] +foo(1, f=1) #: (1,) (f: 1) Tuple[float] foo(1, 2.1, 3, z=2) #: (1, 2.1, 3) (z: 2) Tuple[float,float,float] def sum(x: Generator[int]): @@ -517,7 +517,7 @@ foo(1, 2, 3) #: a (1, 2, 3) #: k (x: 1) foo(1, 2, 3, 4) -#: 1 2 3 (4) () +#: 1 2 3 (4,) () #: a (1, 2, 4, 3) #: k (x: 1) foo(1, 2, zamboni=3) diff --git a/test/parser/typecheck_stmt.codon b/test/parser/typecheck_stmt.codon index c93917a8..c5878757 100644 --- a/test/parser/typecheck_stmt.codon +++ b/test/parser/typecheck_stmt.codon @@ -235,7 +235,7 @@ print foo(N=1, x=2.0) #: 1.41421 print foo(N=1, x=(1, 'bar')) #: foo: bar print foo(N=1, x=(1, 2)) #: len 2 print foo(N=3, x=(1, 2)) #: () -print foo(N=1, x=(1, 2, 3)) #: (3) +print foo(N=1, x=(1, 2, 3)) #: (3,) #%% try_throw,barebones class MyError(Static[Exception]): diff --git a/test/parser/types.codon b/test/parser/types.codon index 02829c3e..5ce6da7c 100644 --- a/test/parser/types.codon +++ b/test/parser/types.codon @@ -940,9 +940,9 @@ print zoo(2, 3) print zoo('s', 3) #: decorating zoo[...,...,...] #: decorator (2, 3) () -#: zoo: 5, 2, (3) +#: zoo: 5, 2, (3,) #: decorator ('s', 3) () -#: zoo: 5, s, (3) +#: zoo: 5, s, (3,) def mydecorator(func): def inner(): @@ -1154,13 +1154,13 @@ call(foo) def foo(a:int, *b: float): return f"{a}_{b}", a+b[0] call(foo) -#: ('1_(2)', 3) +#: ('1_(2,)', 3) def call(f: Callable[[int,int],str]): print(f(1, 2)) def foo(a: int, *b: int, **kw): return f"{a}_{b}_{kw}" call(foo(zzz=1.1, ...)) -#: 1_(2)_(zzz: 1.1) +#: 1_(2,)_(zzz: 1.1) #%% traits_error,barebones def t[T](x: T, key: Optional[Callable[[T], S]] = None, S: type = NoneType):