Skip to content

Commit

Permalink
Support import renaming through at-compat macro.
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikekre committed Oct 19, 2020
1 parent 786d0d8 commit 105bc22
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Compat"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.20.0"
version = "3.21.0"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ changes in `julia`.

## Supported features

* Import renaming is available through the `@compat` macro, e.g. `@compat import LinearAlgebra as LA` and
`@compat import LinearAlgebra: cholesky as c, lu as l`. *Note:* Import renaming of macros is not
supported due to differences in parsing behavior ([#37396]). (since Compat 3.21).

* `Compat.parseatom(text::AbstractString, pos::Integer; filename="none")` parses a single
atom from `text` starting at index `pos`. Returns a `Tuple` consisting of the
parsed expression and the index to resume parsing from. ([#35243]) (since Compat 3.20)
Expand Down Expand Up @@ -219,3 +223,4 @@ Note that you should specify the correct minimum version for `Compat` in the
[#37559]: https://github.com/JuliaLang/julia/pull/37559
[#29634]: https://github.com/JuliaLang/julia/pull/29634
[#35243]: https://github.com/JuliaLang/julia/pull/35243
[#37396]: https://github.com/JuliaLang/julia/pull/37396
50 changes: 50 additions & 0 deletions src/compatmacro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,53 @@ _compat(ex) = ex
macro compat(ex)
esc(_compat(ex))
end

# Only the import-renaming usage results in multiple arguments.
# On versions where renaming is supported natively it parses as a
# single expression and thus takes the single-argument @compat
# code-path above
macro compat(ex, exprs...)
@assert VERSION < v"1.6.0-DEV.1157"
if length(exprs) == 2 && Meta.isexpr(ex, :import, 1) && Meta.isexpr(ex.args[1], :.) &&
exprs[1] === :as && exprs[2] isa Symbol
# Matches "import Module(.Submodule) as a"
lhs = Symbol[ex.args[1].args...]
alias = exprs[2]
return _create_import_expression([lhs => alias])
elseif Meta.isexpr(ex, [:import, :using], 1) &&
Meta.isexpr(ex.args[1], :(:)) && length(exprs) % 2 == 0 &&
all(x -> x === :as, exprs[1:2:end-1]) &&
all(x -> Meta.isexpr(x, :tuple, 2), exprs[2:2:end-2]) &&
exprs[end] isa Symbol
# Matches "(import|using) Module(.Submodule): a as b(, c as d)
syms = Symbol[ ex.args[1].args[2].args[1] ]
foreach(x -> x isa Symbol ? push!(syms, x) : append!(syms, x.args), exprs[2:2:end])

path_aliases = Pair{Vector{Symbol},Symbol}[]
init = ex.args[1].args[1].args
for i in 1:2:length(syms)
push!(path_aliases, Symbol[init; syms[i]] => syms[i+1])
end
return _create_import_expression(path_aliases)
else
throw(ArgumentError("invalid use of @compat"))
end
end

function _create_import_expression(path_aliases::Vector{Pair{Vector{Symbol}, Symbol}})
# Create an gensymd baremodule to hide names in
s = gensym()
# Create all import/const exprs
import_exprs = Expr[]
const_exprs = Expr[]
for (path, alias) in path_aliases
import_expr = Expr(:import, Expr(:., path...))
push!(import_exprs, import_expr)
rhs_expr = Expr(:escape, Expr(:., s, QuoteNode(last(path))))
const_expr = Expr(:const, Expr(:global, Expr(:(=), alias, rhs_expr)))
push!(const_exprs, const_expr)
end
module_expr = Expr(:module, false, Expr(:escape, s), Expr(:block, import_exprs...))
return_expr = Expr(:toplevel, module_expr, const_exprs..., nothing)
return return_expr
end
27 changes: 26 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -753,4 +753,29 @@ end

include("iterators.jl")

nothing
# Import renaming, https://github.com/JuliaLang/julia/pull/37396,
# and https://github.com/JuliaLang/julia/pull/37965
module ImportRename
using Compat
@compat import LinearAlgebra as LA
@compat import LinearAlgebra.BLAS as BL
@compat import LinearAlgebra.BLAS: dotc as dc
@compat import LinearAlgebra: cholesky as chol, lu as lufact
@compat using LinearAlgebra.BLAS: hemm as hm
end

import .ImportRename
import LinearAlgebra

@testset "import renaming" begin
@test ImportRename.LA === LinearAlgebra
@test !isdefined(ImportRename, :LinearAlgebra)
@test ImportRename.BL === LinearAlgebra.BLAS
@test !isdefined(ImportRename, :BLAS)
@test ImportRename.dc === LinearAlgebra.BLAS.dotc
@test !isdefined(ImportRename, :dotc)
@test ImportRename.chol === LinearAlgebra.cholesky
@test ImportRename.lufact === LinearAlgebra.lu
@test ImportRename.hm === LinearAlgebra.BLAS.hemm
@test !isdefined(ImportRename, :hemm)
end

0 comments on commit 105bc22

Please sign in to comment.