diff --git a/src/IntervalSets.jl b/src/IntervalSets.jl index 4dac1da..5e5ce35 100644 --- a/src/IntervalSets.jl +++ b/src/IntervalSets.jl @@ -4,7 +4,7 @@ using Base: @pure import Base: eltype, convert, show, in, length, isempty, isequal, isapprox, issubset, ==, hash, union, intersect, minimum, maximum, extrema, range, clamp, mod, float, ⊇, ⊊, ⊋ -export AbstractInterval, Interval, OpenInterval, ClosedInterval, +export AbstractInterval, Interval, OpenInterval, ClosedInterval, @iv_str, ⊇, .., ±, ordered, width, leftendpoint, rightendpoint, endpoints, isopenset, isclosedset, isleftclosed, isrightclosed, isleftopen, isrightopen, closedendpoints, diff --git a/src/interval.jl b/src/interval.jl index 0496068..b63ffb4 100644 --- a/src/interval.jl +++ b/src/interval.jl @@ -38,6 +38,33 @@ Interval(i::AbstractInterval) = Interval{isleftclosed(i) ? (:closed) : (:open), isrightclosed(i) ? (:closed) : (:open)}(i) Interval(i::TypedEndpointsInterval{L,R}) where {L,R} = Interval{L,R}(i) +macro iv_str(s) + msg = "Invalid expresson `$s`" + for (reg, f) ∈ ( + (r"^\[(.*)\)$", Interval{:closed, :open}), + (r"^\((.*)\)$", Interval{:open, :open}), + (r"^\((.*)\]$", Interval{:open, :closed}), + (r"^\[(.*)\]$", Interval{:closed, :closed}), + ) + m = match(reg, s) + if !isnothing(m) + try + args = Meta.parse("("*m.captures[1]*",)") + if args.head === :incomplete + return :(throw(ErrorException("$($msg)"))) + elseif length(args.args) ≠ 2 + return :(throw(ErrorException("$($msg)"))) + else + return :($f($(esc(args))...)) + end + catch + return :(throw(ErrorException("$($msg)"))) + end + end + end + return :(throw(ErrorException("$($msg)"))) +end + endpoints(i::Interval) = (i.left, i.right) for L in (:(:open),:(:closed)), R in (:(:open),:(:closed)) diff --git a/test/runtests.jl b/test/runtests.jl index f2db5c5..4868459 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -35,6 +35,30 @@ struct IncompleteInterval <: AbstractInterval{Int} end @test ordered(1, 2) == (1, 2) @test ordered(Float16(1), 2) == (1, 2) + @testset "iv_str macro" begin + @test iv"[1,2]" === 1..2 + @test iv"[1,2)" === Interval{:closed, :open}(1, 2) + @test iv"(1,2]" === Interval{:open, :closed}(1, 2) + @test iv"(1,2)" === OpenInterval(1, 2) + + for (a,b) in ((1,2), (1.4,3.9), (ℯ,π)) + @test iv"[a,b]" === a..b + @test iv"[a,b)" === Interval{:closed, :open}(a, b) + @test iv"(a,b]" === Interval{:open, :closed}(a, b) + @test iv"(a,b)" === OpenInterval(a, b) + end + + @test_throws Exception iv"[(1,2)]" + @test_throws Exception iv"[1,2,]" + @test_throws Exception iv"[(1,2]" + @test_throws Exception iv"[(1,,2]" + @test_throws Exception iv"[1..2]" + @test_throws Exception iv"(1..2)" + @test_throws Exception iv"[1...2]" + @test_throws Exception iv"(1...2)" + @test_throws Exception iv"1..2" + end + @testset "Basic Closed Sets" begin @test_throws ErrorException :a .. "b" @test_throws ErrorException 1 .. missing