Skip to content

Commit dcb3d8a

Browse files
authoredFeb 16, 2025··
Use shorter and more robust l-value and r-value tracking for underscore replacement (#169)
* Use more robust l-value and r-value tracking and add test * Simplify * Add tests * Skip a test on 1.0 because the test itself fails to parse
1 parent dceed59 commit dcb3d8a

File tree

2 files changed

+30
-11
lines changed

2 files changed

+30
-11
lines changed
 

‎src/macro_tools.jl

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
"""
2-
substitute_underscores(expr, var) -> new, changed
2+
substitute_underscores(expr, var, right=false) -> new, changed
33
44
Replace all occurrences of `_` in `expr` with `var` and return the new expression and a Bool
55
indicating whether the expression was changed.
6+
7+
If `right` is `true`, then expr is in an approximation of r-value position
68
"""
7-
substitute_underscores(f::Symbol, var::Symbol) = f === :_ ? (var, true) : (f, false)
8-
substitute_underscores(f, ::Symbol) = f, false
9-
function substitute_underscores(ex::Expr, var::Symbol)
9+
substitute_underscores(ex, var::Symbol) = substitute_underscores(ex, var, true)
10+
substitute_underscores(s::Symbol, var::Symbol, right) = right && s === :_ ? (var, true) : (s, false)
11+
substitute_underscores(s, ::Symbol, _) = s, false
12+
function substitute_underscores(ex::Expr, var::Symbol, right)
1013
changed = false
1114
args = similar(ex.args)
12-
i = firstindex(args)
13-
if ex.head in (:(=), :->, :function)
14-
args[i] = ex.args[i]
15-
i += 1
16-
end
17-
for i in i:lastindex(args)
18-
args[i], c = substitute_underscores(ex.args[i], var)
15+
for i in eachindex(args)
16+
force_left = (i == 1 && ex.head in (:(=), :->, :function))
17+
force_right = ex.head == :(::) && i == 2 || ex.head in (:ref, :.)
18+
args[i], c = substitute_underscores(ex.args[i], var, force_right || right && !force_left)
1919
changed |= c
2020
end
2121
changed ? exprarray(ex.head, args) : ex, changed

‎test/runtests.jl

+19
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,25 @@ else
492492
@testset "Issue #156, compat with old constructor" begin
493493
@test Chairmarks.Sample(0,fill(NaN, 8)...) isa Chairmarks.Sample
494494
end
495+
496+
@testset "Issue #167, r-value and l-value detection" begin
497+
@b [0] _[1] = 5 seconds=.01
498+
@b 1 [0][_] = 5 seconds=.01
499+
@b 1 [0][_] seconds=.01
500+
@b Int 0::_ seconds=.01
501+
@b Int x::_ = 5 seconds=.01
502+
@b Int x::_ = 5.0 seconds=.01
503+
@test_throws InexactError @b Int x::_ = 5.5
504+
@b 1,2 (_, _) = _ seconds=.01
505+
@test_throws BoundsError @b 2 (_, _) = _
506+
@b 10 for _ in 1:_ rand(10)[_] = 5.0 end seconds=.01
507+
@static if VERSION >= v"1.6"
508+
mutable struct T167 # Type definition not allowed inside a local scope in Julia 1.0
509+
x::Int
510+
end
511+
@b T167(5) _.x = 7
512+
end
513+
end
495514
end
496515

497516
@testset "Statistics Extension" begin

0 commit comments

Comments
 (0)
Please sign in to comment.