Skip to content

Commit 5ee03f2

Browse files
authored
Improve Expr comparison code for registry testing (#175)
Add special cases to explicitly allow a few incompatibilities for cases where the reference parser has bugs: * `0x1.8p23f` is a `Float64` literal, with the trailing `f` ignored (also `0x1p1f0`) * The macrocall in `"@f(a=1) do\nend"` is not the same as the call in `@f(a=1)` * `global (x,y)` is the same as `global x,y` * Triple quoted indentation - `"\"\"\"\n a\n \n b\"\"\""` parses to "a\n \nb"
1 parent f7ad15f commit 5ee03f2

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

test/test_utils.jl

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,79 @@ function parse_diff(text, showfunc=dump)
6868
show_expr_text_diff(stdout, showfunc, ex, fl_ex)
6969
end
7070

71+
function kw_to_eq(ex)
72+
return Meta.isexpr(:kw, ex) ? Expr(:(=), ex.args...) : ex
73+
end
74+
75+
function triple_string_roughly_equal(str, fl_str)
76+
# Allow some leeway for a bug in the reference parser with
77+
# triple quoted strings
78+
lines = split(str, '\n')
79+
fl_lines = split(fl_str, '\n')
80+
if length(lines) != length(fl_lines)
81+
return false
82+
end
83+
for (line1, line2) in zip(lines, fl_lines)
84+
if !all(c in " \t" for c in line2) && !endswith(line1, line2)
85+
return false
86+
end
87+
end
88+
return true
89+
end
90+
91+
# Compare Expr from reference parser expression to JuliaSyntax parser, ignoring
92+
# differences due to bugs in the reference parser.
93+
function exprs_roughly_equal(fl_ex, ex)
94+
if fl_ex isa Float64 && Meta.isexpr(ex, :call, 3) &&
95+
ex.args[1] == :* &&
96+
ex.args[2] == fl_ex &&
97+
(ex.args[3] == :f || ex.args[3] == :f0)
98+
# 0x1p0f
99+
return true
100+
elseif !(fl_ex isa Expr) || !(ex isa Expr)
101+
if fl_ex isa String && ex isa String
102+
if fl_ex == ex
103+
return true
104+
else
105+
return triple_string_roughly_equal(ex, fl_ex)
106+
end
107+
else
108+
return fl_ex == ex
109+
end
110+
end
111+
if fl_ex.head != ex.head
112+
return false
113+
end
114+
h = ex.head
115+
fl_args = fl_ex.args
116+
args = ex.args
117+
if ex.head in (:block, :quote, :toplevel)
118+
fl_args = filter(x->!(x isa LineNumberNode), fl_args)
119+
args = filter(x->!(x isa LineNumberNode), args)
120+
end
121+
if (h == :global || h == :local) && length(args) == 1 && Meta.isexpr(args[1], :tuple)
122+
# Allow invalid syntax like `global (x, y)`
123+
args = args[1].args
124+
end
125+
if length(fl_args) != length(args)
126+
return false
127+
end
128+
if h == :do && length(args) >= 1 && Meta.isexpr(fl_args[1], :macrocall)
129+
# Macrocalls with do, as in `@f(a=1) do\nend` use :kw in the
130+
# reference parser for the `a=1`, but we regard this as a bug.
131+
fl_args = copy(fl_args)
132+
fl_args[1] = Expr(:macrocall, map(kw_to_eq, args[1].args)...)
133+
end
134+
for i = 1:length(args)
135+
flarg = fl_args[i]
136+
arg = args[i]
137+
if !exprs_roughly_equal(flarg, arg)
138+
return false
139+
end
140+
end
141+
return true
142+
end
143+
71144
function parsers_agree_on_file(filename; show_diff=false)
72145
text = try
73146
read(filename, String)
@@ -93,6 +166,8 @@ function parsers_agree_on_file(filename; show_diff=false)
93166
return !JuliaSyntax.any_error(stream) &&
94167
JuliaSyntax.remove_linenums!(ex) ==
95168
JuliaSyntax.remove_linenums!(fl_ex)
169+
# Could alternatively use
170+
# exprs_roughly_equal(fl_ex, ex)
96171
catch exc
97172
@error "Parsing failed" filename exception=current_exceptions()
98173
return false
@@ -308,3 +383,18 @@ function parse_sexpr(code)
308383
st
309384
end
310385

386+
387+
@testset "Test tools" begin
388+
@test exprs_roughly_equal(Expr(:global, :x, :y),
389+
Expr(:global, Expr(:tuple, :x, :y)))
390+
@test exprs_roughly_equal(Expr(:local, :x, :y),
391+
Expr(:local, Expr(:tuple, :x, :y)))
392+
@test exprs_roughly_equal(1.5,
393+
Expr(:call, :*, 1.5, :f))
394+
@test exprs_roughly_equal(1.5,
395+
Expr(:call, :*, 1.5, :f0))
396+
@test exprs_roughly_equal(Expr(:do, Expr(:macrocall, Symbol("@f"), LineNumberNode(1), Expr(:kw, :a, 1)),
397+
Expr(:->, Expr(:tuple), Expr(:block, LineNumberNode(1)))),
398+
Expr(:do, Expr(:macrocall, Symbol("@f"), LineNumberNode(1), Expr(:(=), :a, 1)),
399+
Expr(:->, Expr(:tuple), Expr(:block, LineNumberNode(1)))))
400+
end

tools/check_all_packages.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Logging.with_logger(logger) do
3131
@assert Meta.isexpr(e2, :toplevel)
3232
try
3333
e1 = JuliaSyntax.parseall(Expr, code, filename=fpath)
34-
if JuliaSyntax.remove_linenums!(e1) != JuliaSyntax.remove_linenums!(e2)
34+
if !exprs_roughly_equal(e2, e1)
3535
mismatch_count += 1
3636
@error("Parsers succeed but disagree",
3737
fpath,

0 commit comments

Comments
 (0)