Skip to content

Commit dcddbca

Browse files
authored
show: improve handling of . syntax printing (#24994)
1 parent 8b01dfa commit dcddbca

File tree

3 files changed

+73
-25
lines changed

3 files changed

+73
-25
lines changed

base/show.jl

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,16 @@ show_unquoted(io::IO, sym::Symbol, ::Int, ::Int) = print(io, sym)
813813
show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.line, ex.file)
814814
show_unquoted(io::IO, ex::LabelNode, ::Int, ::Int) = print(io, ex.label, ": ")
815815
show_unquoted(io::IO, ex::GotoNode, ::Int, ::Int) = print(io, "goto ", ex.label)
816-
show_unquoted(io::IO, ex::GlobalRef, ::Int, ::Int) = print(io, ex.mod, '.', ex.name)
816+
function show_unquoted(io::IO, ex::GlobalRef, ::Int, ::Int)
817+
print(io, ex.mod)
818+
print(io, '.')
819+
quoted = !isidentifier(ex.name)
820+
parens = quoted && !isoperator(ex.name)
821+
quoted && print(io, ':')
822+
parens && print(io, '(')
823+
print(io, ex.name)
824+
parens && print(io, ')')
825+
end
817826

818827
function show_unquoted(io::IO, ex::Slot, ::Int, ::Int)
819828
typ = isa(ex,TypedSlot) ? ex.typ : Any
@@ -908,11 +917,29 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int)
908917
if !emphstate && ex.typ === Any
909918
show_type = false
910919
end
920+
unhandled = false
911921
# dot (i.e. "x.y"), but not compact broadcast exps
912-
if head === :(.) && !is_expr(args[2], :tuple)
913-
func_prec = operator_precedence(head)
914-
args_ = (args[1], (is_quoted(arg) && !is_quoted(unquoted(arg)) ? unquoted(arg) : arg for arg in args[2:end])...)
915-
show_list(io, args_, head, indent, func_prec)
922+
if head === :(.) && (length(args) != 2 || !is_expr(args[2], :tuple))
923+
if length(args) == 2 && is_quoted(args[2])
924+
item = args[1]
925+
# field
926+
field = unquoted(args[2])
927+
parens = !is_quoted(item) && !(item isa Symbol && isidentifier(item))
928+
parens && print(io, '(')
929+
show_unquoted(io, item, indent)
930+
parens && print(io, ')')
931+
# .
932+
print(io, '.')
933+
# item
934+
parens = !(field isa Symbol)
935+
quoted = parens || isoperator(field)
936+
quoted && print(io, ':')
937+
parens && print(io, '(')
938+
show_unquoted(io, field, indent)
939+
parens && print(io, ')')
940+
else
941+
unhandled = true
942+
end
916943

917944
# infix (i.e. "x <: y" or "x = y")
918945
elseif (head in expr_infix_any && nargs==2) || (head === :(:) && nargs==3)
@@ -1236,6 +1263,9 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int)
12361263
show_type = false
12371264
# print anything else as "Expr(head, args...)"
12381265
else
1266+
unhandled = true
1267+
end
1268+
if unhandled
12391269
if head !== :invoke
12401270
show_type = false
12411271
end

src/rtutils.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,8 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt
764764
}
765765
else if (vt == jl_globalref_type) {
766766
n += jl_static_show_x(out, (jl_value_t*)jl_globalref_mod(v), depth);
767-
n += jl_printf(out, ".%s", jl_symbol_name(jl_globalref_name(v)));
767+
char *name = jl_symbol_name(jl_globalref_name(v));
768+
n += jl_printf(out, jl_is_identifier(name) ? ".%s" : ".:(%s)", name);
768769
}
769770
else if (vt == jl_labelnode_type) {
770771
n += jl_printf(out, "%" PRIuPTR ":", jl_labelnode_label(v));

test/show.jl

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,24 @@ end
3535
# expression printing
3636

3737
macro test_repr(x)
38-
quote
39-
# Note: We can't just compare x1 and x2 because interpolated
40-
# strings get converted to string Exprs by the first show().
41-
# This could produce a few false positives, but until string
42-
# interpolation works we don't really have a choice.
43-
let
44-
local x1 = Meta.parse($x)
45-
local x2 = eval(Meta.parse(repr(x1)))
46-
local x3 = eval(Meta.parse(repr(x2)))
47-
if x3 != x1
48-
error(string(
49-
"repr test failed:",
50-
"\noriginal: ", $x,
51-
"\n\nparsed: ", x2, "\n", sprint(dump, x2),
52-
"\n\nreparsed: ", x3, "\n", sprint(dump, x3)
53-
))
54-
end
55-
end
38+
# this is a macro instead of function so we can avoid getting useful backtraces :)
39+
return :(test_repr($(esc(x))))
40+
end
41+
function test_repr(x::String)
42+
# Note: We can't just compare x1 and x2 because interpolated
43+
# strings get converted to string Exprs by the first show().
44+
# This could produce a few false positives, but until string
45+
# interpolation works we don't really have a choice.
46+
x1 = Meta.parse(x)
47+
x2 = eval(Meta.parse(repr(x1)))
48+
x3 = eval(Meta.parse(repr(x2)))
49+
if x3 != x1
50+
error(string(
51+
"repr test failed:",
52+
"\noriginal: ", x,
53+
"\n\nparsed: ", x2, "\n", sprint(dump, x2),
54+
"\n\nreparsed: ", x3, "\n", sprint(dump, x3)
55+
))
5656
end
5757
end
5858

@@ -83,7 +83,8 @@ end
8383
@test_repr "x^-(y+z)"
8484
@test_repr "x^-f(y+z)"
8585
@test_repr "+(w-x)^-f(y+z)"
86-
#@test_repr "w = (x = y) = z" # Doesn't pass, but it's an invalid assignment loc
86+
@test_repr "w = ((x = y) = z)" # parens aren't necessary, but not wrong
87+
@test_repr "w = ((x, y) = z)" # parens aren't necessary, but not wrong
8788
@test_repr "a & b && c"
8889
@test_repr "a & (b && c)"
8990
@test_repr "(a => b) in c"
@@ -782,6 +783,22 @@ end
782783
@test repr(:(f.(X))) == ":(f.(X))"
783784
@test repr(:(f.())) == ":(f.())"
784785

786+
# pretty-printing of other `.` exprs
787+
test_repr("a.b")
788+
test_repr("a.in")
789+
test_repr(":a.b")
790+
test_repr("a.:+")
791+
test_repr("(+).a")
792+
test_repr("(+).:-")
793+
test_repr("(!).:~")
794+
test_repr("a.:(begin
795+
#= none:3 =#
796+
end)")
797+
@test repr(Expr(:., :a, :b, :c)) == ":(\$(Expr(:., :a, :b, :c)))"
798+
@test repr(Expr(:., :a, :b)) == ":(\$(Expr(:., :a, :b)))"
799+
@test repr(Expr(:., :a)) == ":(\$(Expr(:., :a)))"
800+
@test repr(Expr(:.)) == ":(\$(Expr(:.)))"
801+
785802
# Test compact printing of homogeneous tuples
786803
@test repr(NTuple{7,Int64}) == "NTuple{7,Int64}"
787804
@test repr(Tuple{Float64, Float64, Float64, Float64}) == "NTuple{4,Float64}"

0 commit comments

Comments
 (0)